NSInvocation返回值,但使用EXC_BAD_ACCESS使应用程序崩溃 [英] NSInvocation returns value but makes app crash with EXC_BAD_ACCESS

查看:187
本文介绍了NSInvocation返回值,但使用EXC_BAD_ACCESS使应用程序崩溃的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个要迭代并寻找特定标志的数组.如果标志值为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打印预期的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;

I have an array which I am iterating and looking for a particular flag. If the flag value is nil, I am calling a method which generates an invocation object and returns the result of invocation.

My code structure is as follows

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);
        }
 }

Method which generates 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;
}

In the for loop, without the method call for NSInvocation ([self ....]), the loop just executes fine and not crashing. But when I introduce the method to invoke NSInvocation, I am able to see the NSLog in for loop prints expected NSArray result but it crashes with error message EXC_BAD_ACCESS.

I am not able to figure out why it fails even though NSInvocation returns proper result. Without NSInvocation, for loop is not getting crashed.

Any suggestions would be helpful.

Thanks

解决方案

I am guessing you are using ARC?

The problem is with the line [invocation getReturnValue:&resultSet];. getReturnValue: just copies the bytes of the return value into the given memory buffer, regardless of type. It doesn't know or care about memory management if the return type is a retainable object pointer type. Since resultSet is a __strong variable of object pointer type, ARC assumes that any value that has been put into the variable has been retained, and thus will release it when it goes out of scope. That is not true in this case, so it crashes. (Also, the array that you had resultSet originally point to will be leaked, since getReturnValue: overwrites that value without releasing it. Why you even made that variable point to an object in the first place is beyond me.)

The solution is that you must give a pointer to a non-retained type to getReturnValue:. Either:

NSArray * __unsafe_unretained tempResultSet;
[invocation getReturnValue:&tempResultSet];
NSArray *resultSet = tempResultSet;

or:

void *tempResultSet;
[invocation getReturnValue:&tempResultSet];
NSArray *resultSet = (__bridge NSArray *)tempResultSet;

这篇关于NSInvocation返回值,但使用EXC_BAD_ACCESS使应用程序崩溃的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆