启用ARC的设备上的iOS崩溃

Sed*_*ien 7 memory-management objective-c ios automatic-ref-counting

我遇到了一个让我完全难过的问题.我将用代码示例说明:

@interface Crasher ()
@property (nonatomic, strong) NSArray *array;
@end

@implementation Crasher

- (void)crash;
{
  NSMutableArray *mutable = [NSMutableArray array];
  NSArray *items = @[@0, @1, @2, @3];

  if ([@YES boolValue])
  {
    [items enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
      [mutable addObject:obj];
    }];
  }
  else
  {
    [items enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
      [mutable addObject:obj];
    }];
  }

  [self setArray:mutable];
}

@end
Run Code Online (Sandbox Code Playgroud)

[self setArray:mutable]启用ARC并在设备上运行时,上面的代码在线路上崩溃.代码永远不会在模拟器上崩溃,也不会在禁用ARC的设备上崩溃.使用NSZombieEnabled表示setter正在尝试保留已经解除分配的数组.

如果第二个[mutable addObject:obj]调用被注释掉,它不会崩溃(但这个代码从未在第一个地方执行).

我上传了一个项目,向Github演示了这次崩溃aidansteele/arc-crash.我正在使用Xcode 4.5.2.它似乎不会出现在Xcode 4.6上,但仍然在开发人员预览中.我究竟做错了什么?


解决这个问题的答案(在问题上,以便我有更多的空间),我不相信问题在于,-[NSArray enumerateObjectsUsingBlock:]如果我改变该方法调用以使用以下-[NSArray(Functional) each:]调用问题仍然存在.

@interface NSArray (Functional)
- (void)each:(void (^)(id obj))action;
@end

@implementation NSArray (Functional)

- (void)each:(void (^)(id))action;
{
  for (NSUInteger idx = 0; idx < [self count]; idx++)
  {
    action([self objectAtIndex:idx]);
  }
}

@end
Run Code Online (Sandbox Code Playgroud)

Val*_*adu 0

enumerateObjectsUsingBlock我认为您的 SDK 版本的方法存在问题 。也许您应该阅读新 SDK 的发行说明或旧 SDK 的已知问题以了解更多信息。因此,发生的情况是,您的保留计数在您调用 之前都很好enumerateObjectsUsingBlock。该方法退出后,您的指针指向一些垃圾。

解决这个问题的一种方法是对你的收藏负责,并承诺在退出前不会丢弃它enumerateObjectsUsingBlock。虽然修复了,但它并没有解决核心问题,正如我上面所说,我认为它存在于enumerateObjectsUsingBlock. 这是一个有效的代码(周围)。

#import "Crasher.h"

@interface Crasher ()
@property (nonatomic, strong) NSArray *array;
@end

@implementation Crasher

- (void)crash;
{
  __block NSMutableArray *mutable = [NSMutableArray array];
  NSArray *items = @[@0, @1, @2, @3];

  if ([@YES boolValue])
  {
    [items enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
      [mutable addObject:obj];
    }];
  }
  else
  {
    [items enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
      [mutable addObject:obj];
    }];
  }

    NSLog(@"%@", mutable);

  [self setArray:mutable];
}

@end
Run Code Online (Sandbox Code Playgroud)