在使用NSInvocation的過程中,遇到一個問題。那就是在獲取返回結果後,app很快crash。示例如下:
NSMethodSignature *methodSignature = [FlightOperations instanceMethodSignatureForSelector:NSSelectorFromString(action)];
NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:methodSignature];
[invocation setTarget:fOps];
[invocation setSelector:NSSelectorFromString(action)];
[invocation setArgument:&flightPoint atIndex:2];
NSArray *resultSet;
[invocation invoke];
[invocation getReturnValue:&resultSet];
return resultSet;
在設置Enable Zombies後發現,是由於系統多次釋放NSArray * resultSet造成的非法內存訪問。
原因是在arc模式下,getReturnValue:僅僅是從invocation的返回值拷貝到指定的內存地址,如果返回值是一個NSObject對象的話,是沒有處理起內存管理的。而我們在定義resultSet時使用的是__strong類型的指針對象,arc就會假設該內存塊已被retain(實際沒有),當resultSet出了定義域釋放時,導致該crash。假如在定義之前有賦值的話,還會造成內存泄露的問題。
解決辦法:
使用一個unretain的對象來獲取返回值,或者 用void *指針來保存返回值,然後用__bridge來轉化爲OC對象。
NSArray * __unsafe_unretained tempResultSet;
[invocation getReturnValue:&tempResultSet];
NSArray *resultSet = tempResultSet;
或者
void *tempResultSet;
[invocation getReturnValue:&tempResultSet];
NSArray *resultSet = (__bridge NSArray *)tempResultSet;