【问题标题】:NSArray countByEnumeratingWithState sent to deallocated instanceNSArray countByEnumeratingWithState 发送到已释放的实例
【发布时间】:2014-11-20 22:35:26
【问题描述】:

我收到此错误:

没有堆栈跟踪。

-[__NSArrayI countByEnumeratingWithState:objects:count:]: message sent to deallocated instance

这个方法叫什么?

是否可以确定这是什么?我有僵尸,但没有看到来电者。

这里是线程 1:

其他唯一可点击的线路是来自 AFNetworking ([runloop run]) 的线路。我刚刚升级了我的 AFNetworking pod。

+ (void)networkRequestThreadEntryPoint:(id)__unused object {
    @autoreleasepool {
        [[NSThread currentThread] setName:@"AFNetworking"];

        NSRunLoop *runLoop = [NSRunLoop currentRunLoop];
        [runLoop addPort:[NSMachPort port] forMode:NSDefaultRunLoopMode];
        [runLoop run];
    }
}

编辑:@autoreleasepool 上的上述断点甚至没有被命中。我确实在另一个线程中的同一崩溃的代码中找到了这个(上次没有看到这个):,在archiveSuccessful = line

- (void)archiveContent:(BOOL)changeNotification userInfo:(NSDictionary *)userInfo {
    BOOL archiveSuccessful;
    @synchronized(self) {
        archiveSuccessful = [NSKeyedArchiver archiveRootObject:self.contentDictionary toFile:self.filePath];
    }
    if (archiveSuccessful) {
        if(changeNotification && self.contentChangedNotificationName) {
            [[NSNotificationCenter defaultCenter] postNotificationName:self.contentChangedNotificationName object:nil userInfo:userInfo];
        }
    } else {
        NSAssert(NO, @"Saving archive to %@ was not successful", self.filePath);
    }
}

这是被调用的

- (void)addObjects:(NSArray *)objects changeNotification:(BOOL)changeNotification {
    [objects enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
        if([obj conformsToProtocol:NSProtocolFromString(@"DRLocalObject")]) {
            [self addObject:obj changeNotification:NO];
        }
    }];

[self addObject... 行的调试器打印输出

(lldb) po obj
0x00007fde0ff56770

(lldb) po 0x00007fde0ff56770
140591727208304

编辑:

threadMain: 从 Google 分析中调用。项目查找和快速打开显示没有名为 threadMain: 的选择器

【问题讨论】:

  • 对数组进行快速枚举时调用。
  • 如 for (myobject *f in myArray)?我可以搜索什么代码在项目中找到它?
  • 您是否添加了异常断点以查看它是否确定了违规行?
  • 是的,我有所有异常断点。
  • 堆栈跟踪消息的描述性足以告诉您,您正在对已释放实例调用 countByEnumeratingWithState。请检查如何解除分配?

标签: ios objective-c afnetworking google-analytics-sdk


【解决方案1】:

(这是一个很难通过 StackOverflow 调试的错误,所以我只是在这里给出指点。)

几乎可以肯定,您正在修改多个线程上的某些数据结构。鉴于具体情况,我怀疑有一个数组是某个对象的 ivar,当您在其他线程上枚举它时,您将其放在一个线程上。您可以通过解除分配拥有的对象或替换数组来删除它。

您调用@synchronized(self) 的事实强烈表明您在此程序中执行危险线程。在现代 ObjC 中,@synchronized 几乎从来都不是正确的工具。如果您直接使用NSThread,那可能也是您的麻烦之源(AFNetworking 已经足够老,可以通过此方法,但您不应该复制他们的方法)。处理并发的正确工具是 GCD (dispatch_*) 或 NSOperation

您是否验证过self.contentDictionaryself.filePath 的每个突变也是同步的。我特别怀疑self.contentDictionary,因为它可能包含数组。

顺便说一句,在这里正确使用访问器值得称赞,但如果它们不是原子的,如果你在不同的线程上读取和写入它们,它们可能会出现不一致的状态。使它们原子化并不能使它们完全线程安全;您仍然确实需要使用 GCD 或 NSOperation 之类的东西来序列化访问。

您致电@synchronized,然后以相同的方法发布通知这一事实也有些可疑。通知在发布它们的同一线程上同步处理,因此您的通知观察者需要知道它们可能在哪个线程上被调用。

注意,AFNetworking runloop 处理方法中的 crash 是没有意义的。这并没有给你任何真正的暗示。

我会看看你的线程。特别注意对数组(尤其是数组属性)的未受保护访问。并确保使用 GCD 或 NSOperation 序列化所有访问,而不是 @synchronize

【讨论】:

  • 感谢您的指点。当用户登录以获取他们的配置文件数据时,会调用多个异步调度线程。我将调查应用程序中@synchronized 的使用情况,看看如何使用 dispatch 来更新它。
  • Rob,我确实看到了一个 threadMain: 从 Google Analytics 调用。也许那是在调用 NSThread?使用堆栈跟踪更新帖子。
  • 您在这里指的是哪些访问器?在枚举块内?
  • GAI 的东西可能不是问题所在。我怀疑这是您代码中的跨线程访问。访问者是指使用self.contentDictionary 而不是_contentDictionary。小心这种方式将有助于您使这个线程安全。
  • 我停止了崩溃,这与在不合时宜的时间关闭视图控制器有关。标记为正确以获得有关线程的良好提示。
猜你喜欢
  • 2011-06-16
  • 2023-03-13
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多