【问题标题】:NSInvocation returns value but makes app crash with EXC_BAD_ACCESSNSInvocation 返回值但使用 EXC_BAD_ACCESS 使应用程序崩溃
【发布时间】:2014-03-27 21:59:55
【问题描述】:

我有一个数组,我正在迭代并寻找一个特定的标志。如果标志值为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 循环不会崩溃。

任何建议都会有所帮助。

谢谢

【问题讨论】:

  • 您是否有更多关于控制台或调试器崩溃原因的信息?
  • 控制台不显示其他信息。我得到的只是线程 1:EXC_BAD_ACCESS(code=EXC_i386_GPFLT)
  • 设置 NSZombieEnabled。它会给你更多的信息。见stackoverflow.com/questions/2190227/…
  • 试试看能不能得到这里描述的信息:stackoverflow.com/questions/13326550/…
  • 打开僵尸,这就是我得到的“2014-02-25 16:25:42.152 MyPlane[24339:70b] *** -[__NSArrayI release]: message sent to deallocated instance 0x1127717f0” .看起来像是过早的释放。

标签: ios objective-c nsinvocation


【解决方案1】:

这是你不知道返回值是什么类型的情况的解决方案

__weak id weakReturnValue;
[_invocation getReturnValue:&weakReturnValue];
id returnValue = weakReturnValue; // ARC owned strong reference

【讨论】:

    【解决方案2】:

    是的,刚刚发生在 ARC 中。

    我猜这是系统Bug。

    例如:
    【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];
    

    解决以下问题

    案例一:

    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 说的
    欢迎讨论

    【讨论】:

      【解决方案3】:

      我猜你正在使用 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;
      

      【讨论】:

      • 我遇到了同样的问题,这个解决方案就像一个魅力! :)
      • 为此拥抱和亲吻。
      • @newacct 老兄!我在调用时闻到了一些问题,但正如经常发生的那样,一个人过于匆忙地阅读文档并思考......非常感谢!
      猜你喜欢
      • 2015-02-26
      • 1970-01-01
      • 2013-03-08
      • 2021-05-30
      • 2013-07-16
      • 2013-10-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多