由__NSFastEnumerationMutationHandler异常引起的奇怪崩溃

时间:2014-04-08 09:39:41

标签: ios objective-c

有时(不是每次!)当我的应用程序从推送通知触发时,它可能会崩溃。

崩溃的日志是:

0   CoreFoundation                  0x18465a950 __exceptionPreprocess + 132
1   libobjc.A.dylib                 0x190b601fc objc_exception_throw + 60
2   CoreFoundation                  0x18465a384 __NSFastEnumerationMutationHandler + 140
3   Oler                            0x1001976ec __42-[ONotificationListViewController refresh]_block_invoke (ONotificationListViewController.m:88)
4   Oler                            0x1000ec39c __61-[OlerClient notificationListWithOption:onSuccess:onFailure:]_block_invoke (OlerClient.m:623)
5   Oler                            0x1000f7c74 __69-[OlerClient sendVerifiedRequest:url:parameters:onSuccess:onFailure:]_block_invoke (OlerClient.m:1176)
6   Oler                            0x10011ba88 __64-[AFHTTPRequestOperation setCompletionBlockWithSuccess:failure:]_block_invoke146 (AFHTTPRequestOperation.m:137)
7   libdispatch.dylib               0x191138014 _dispatch_call_block_and_release + 24
8   libdispatch.dylib               0x191137fd4 _dispatch_client_callout + 16
9   libdispatch.dylib               0x19113b1dc _dispatch_main_queue_callback_4CF + 336
10  CoreFoundation                  0x18461a62c __CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__ + 12
11  CoreFoundation                  0x18461896c __CFRunLoopRun + 1452
12  CoreFoundation                  0x1845596d0 CFRunLoopRunSpecific + 452
13  GraphicsServices                0x18a23dc0c GSEventRunModal + 168
14  UIKit                           0x18768afdc UIApplicationMain + 1156
15  Oler                            0x1001cdb9c main (main.m:16)
16  libdyld.dylib                   0x191153aa0 start + 4

我相信原因在第3行:

3   Oler                            0x1001976ec __42-[ONotificationListViewController refresh]_block_invoke (ONotificationListViewController.m:88)

我的代码是:

- (void)refresh {
    NSDictionary *option = @{@"offset": @(0),
                             @"limit":  @(99)};

    [[OlerClient sharedClient] notificationListWithOption:option onSuccess:^(NSArray *notifications) {
        [self.pullToRefreshView finishLoading];
        self.notifications = [notifications mutableCopy];

        if (self.ignoreNotificationId > 0) {

            // This is line 88, where the crash happens
            for (ONotification *notif in self.notifications) {
                if (notif.modelId == self.ignoreNotificationId) {
                    [self.notifications removeObject:notif];
                    self.ignoreNotificationId = 0;
                    [[OlerClient sharedClient] markNotificationAsIsRead:notif onSuccess:nil onFailure:nil];
                }
            }
        }

        [self reloadData];

    } onFailure:^(NSError *error) {
        [self.pullToRefreshView finishLoading];
        [OlerUIToolKit showFailureMessage:@"Fail to load notifications:("];
    }];
}

特别是,第88行是代码

for (ONotification *notif in self.notifications) {

谁能告诉我可能出错的地方?我猜是mutableCopy语句吗?

2 个答案:

答案 0 :(得分:5)

在该阵列的快速枚举期间,您无法修改数组。你打电话

[self.notifications removeObject:notif];

在枚举中,这就是你有这个错误的原因。

您可以用

替换循环
for (int i = 0; i <= self.notifications.count i++)

或者您可以使用这样的技巧:

for (ONotification *notif in [self.notifications copy])

答案 1 :(得分:3)

您正在枚举数组并从中删除对象。那是一个不用了!

这发生在这里:

for (ONotification *notif in self.notifications) {
    if (notif.modelId == self.ignoreNotificationId) {
        [self.notifications removeObject:notif];
        self.ignoreNotificationId = 0;
        [[OlerClient sharedClient] markNotificationAsIsRead:notif onSuccess:nil onFailure:nil];
    }
}

只需将要删除的notif对象存储在另一个数组中,在完成枚举后,删除所有存储的notifs