反復して特定のフラグを探している配列があります。フラグ値がnilの場合、呼び出しオブジェクトを生成し、呼び出しの結果を返すメソッドを呼び出しています。
私のコード構造は次のとおりです
for(NSString *key in [taxiPlanes allKeys])
{
Plane *currentPlane = [taxiPlanes objectForKey:key];
if(currentPlane.currentAction == nil)
{
NSString *selector = [[currentPlane planeTakeoffSequence] firstObject];
currentPlane.currentAction = selector;
// Calling for NSInvocation in [self ...]
NSArray *action = [NSArray arrayWithArray:[self operationFromTakeoffAction:currentPlane.currentAction AtPoint:currentPlane.position]];
NSLog(@"%@",action);
}
}
NSInvocationを生成するメソッド
-(NSArray *) operationFromTakeoffAction:(NSString *) action AtPoint:(CGPoint) flightPoint
{
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 = [NSArray alloc]init];
[invocation invoke];
[invocation getReturnValue:&resultSet];
return resultSet;
}
Forループでは、NSInvocation([self ....])のメソッド呼び出しがなくても、ループは正常に実行され、クラッシュしません。しかし、NSInvocationを呼び出すメソッドを導入すると、NSLog in forループが期待されるNSArrayの結果を出力するのを確認できますが、エラーメッセージEXC_BAD_ACCESSでクラッシュします。
NSInvocationが適切な結果を返しても、なぜ失敗するのか理解できません。 NSInvocationがないと、forループはクラッシュしません。
どんな提案も役に立ちます。
ありがとう
ARCを使用していると思いますか?
問題は行[invocation getReturnValue:&resultSet];
にあります。 getReturnValue:
は、タイプに関係なく、戻り値のバイトを指定されたメモリバッファにコピーするだけです。戻り値の型が保持可能なオブジェクトポインタ型であるかどうかは、メモリ管理を認識または考慮しません。 resultSet
はオブジェクトポインタ型の__strong
変数であるため、ARCは変数に入力された値が保持されていると見なし、スコープ外になると解放します。この場合はそうではないので、クラッシュします。 (また、resultSet
が最初に指していた配列は、getReturnValue:
が値を解放せずに上書きするため、リークされます。そもそもその変数がオブジェクトを指すようにした理由は、私。)
解決策は、保持されていない型へのポインターをgetReturnValue:
に指定する必要があることです。どちらか:
NSArray * __unsafe_unretained tempResultSet;
[invocation getReturnValue:&tempResultSet];
NSArray *resultSet = tempResultSet;
または:
void *tempResultSet;
[invocation getReturnValue:&tempResultSet];
NSArray *resultSet = (__bridge NSArray *)tempResultSet;
はい、それはARCで起こったばかりです。
これはシステムのバグだと思います。
例えば:
【iPhone4s + iOS8.4】、【iphone 4 + iOS7.1】(クラッシュ)、
【iPhone6 + iOS9.3】、【iphone 5 + iOS8.4.1】(合格)、
私のテストデモのダウンロードリンク https://github.com/leopardpan/IssuesDemo
元のコード
NSArray *resultSet = [NSArray alloc]init];
[invocation invoke];
[invocation getReturnValue:&resultSet];
以下を解決するには
ケース1:
void *temp = NULL;
[invocation invoke];
[invocation getReturnValue:&temp];
NSArray *resultSet = (__bridge NSArray*)temp;
ケース2:
__weak NSArray *resultSet = [NSArray alloc]init];
[invocation invoke];
[invocation getReturnValue:&resultSet];
ケース3:
__autoreleasing NSArray *resultSet = [NSArray alloc]init];
[invocation invoke];
[invocation getReturnValue:&resultSet];
ケース4:
__unsafe_unretained NSArray *resultSet = [NSArray alloc]init];
[invocation invoke];
[invocation getReturnValue:&resultSet];
Case1の使用をお勧めします。原則は@newacctである必要があります。
話し合いへようこそ
これは、戻り値のタイプがわからない場合のソリューションです。
__weak id weakReturnValue;
[_invocation getReturnValue:&weakReturnValue];
id returnValue = weakReturnValue; // ARC owned strong reference