NSInvocation返回值,但通过EXC_BAD_ACCESS使应用程序崩溃
我有一个数组,我正在迭代并寻找一个特定的标志。 如果标志值为零,我正在调用一个方法来生成一个调用对象并返callback用的结果。
我的代码结构如下
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的for循环打印预期NSArray的结果,但它崩溃与错误消息EXC_BAD_ACCESS。
即使NSInvocation返回正确的结果,我也无法弄清楚它为什么失败。 没有NSInvocation,for循环不会崩溃。
任何的意见都将会有帮助。
谢谢
我猜你正在使用ARC?
问题是与行[invocation getReturnValue:&resultSet];
。 getReturnValue:
只是将返回值的字节复制到给定的内存缓冲区中,而不pipetypes如何。 如果返回types是可保留的对象指针types,它不知道或关心内存pipe理。 由于resultSet
是对象指针types的__strong
variables,因此ARC会假定已放入variables的任何值都被保留,因此在超出作用域时会释放它。 在这种情况下不是这样,所以它崩溃了。 (而且,你最初指向resultSet
的数组将被泄漏,因为getReturnValue:
覆盖该值而不释放它。为什么你甚至把这个variables指向一个对象呢?
解决的办法是,你必须给一个非保留types的指针getReturnValue:
或者:
NSArray * __unsafe_unretained tempResultSet; [invocation getReturnValue:&tempResultSet]; NSArray *resultSet = tempResultSet;
要么:
void *tempResultSet; [invocation getReturnValue:&tempResultSet]; NSArray *resultSet = (__bridge NSArray *)tempResultSet;
是的,这只是发生在ARC。
我猜这是系统Bug。
例如:
【iPhone4s + iOS8.4】,【iphone 4 + iOS7.1】(crash),
【iPhone6 + iOS9.3】,【iphone 5 + iOS8.4.1】(通行证),
我的testing演示下载链接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];
build议使用case1,原则应该是@newacct说的
欢迎来讨论