离开加载集合视图时应用程序崩溃

问题描述 投票:0回答:1

场景:

UINavigationViewController
包含
UICollectionViewControllers
。每个集合视图都需要从 JSON API 获取其数据,这可能需要一些时间。然后集合视图中的每个单元格都会向服务器发送自己的请求,获取缩略图。 (为了清楚起见,我创建了一个序列图来展示我是如何做到这一点的,不包括缩略图请求,我已禁用该请求进行调试):

sequence diagram

代码如下:

-(void)buildDisplayItems
{
    NSLog(@"Collection VC (object: %@) with collection (object: %@) building display items on thread %@ (main thread: %c)", self, self.showingCollection, [NSThread currentThread], [NSThread isMainThread]);
    [self.showingCollection buildDisplayItemsWithPhotoBatch:self.nextBatch++]; // <-- this waits for the server request to be made, come back and get processed into arrays before returning.
    self.photos = self.showingCollection.photos;
    self.collections = self.showingCollection.subcategories;
    // Past this point, I cannot think of how these arrays would possibly get changed to trigger the 'mutated while being enumerated' errors.
    [self.collectionView reloadData];
}

问题是,如果用户在正确的时间导航回导航视图,我会收到以下错误之一:

*** 由于未捕获的异常“NSGenericException”而终止应用程序,原因:“*** Collection 在枚举时发生了变化。”

** 由于未捕获的异常“NSGenericException”而终止应用程序,原因:“*** Collection <__NSSetM: 0x203f26b0> 在枚举时发生了变化。”

*** 由于未捕获的异常“NSInvalidArgumentException”而终止应用程序,原因:“*** -[__NSPlaceholderArray initWithObjects:count:]:尝试从对象[3]插入零对象”

为了使这些错误发生,我必须尝试 3-4 次选择某个项目,以便将其集合视图推送到导航堆栈上,然后快速按后退按钮。显然,前两个错误给我的第一印象是数据源数组正在以某种方式进行修改,但我编写的任何内容都无法做到这一点。然后我想也许每个单元格的缩略图在

cellForItemAtIndexPath
返回后加载就是问题所在,所以我禁用了它,但没有任何改变。

我散布了一些 NSLog,发现这种情况是在集合视图调用其委托方法时发生的。我确保添加以下内容:

-(void)viewWillDisappear:(BOOL)animated
{
    if (self.showingCollection != nil) {
        [self.showingCollection cancelOperations]; //for network requests
        NSLog(@"Collection VC (object: %@) will disappear", self);
    }
}

-(void)dealloc
{
    [[NSNotificationCenter defaultCenter] removeObserver:self];
    self.collectionView.delegate = nil;
    self.collectionView.dataSource = nil;
    self.collectionView = nil;
}

但这并没有帮助阻止错误。事实上,有时当崩溃发生时,并没有“Collection VC will不见”的日志消息。

另一个问题是,发生这些错误时调试器会在主函数中的

UIApplicationMain line
处停止(这是“在所有异常上中断”断点),因此我无法确定错误是如何触发的。我启用了僵尸,但没有来自它们的日志消息。 (编辑:有时它实际上停在一个空线程中,说“错误:地址不包含指向目标文件中某个部分的部分”)

如何设置这些集合视图,以便快速按后退按钮不会导致世界末日?

编辑 我怎样才能知道枚举时正在更改的集合是什么?

更新 我发现这个堆栈溢出线程谈论无法获取堆栈跟踪。每次我遇到上述异常之一时,它都会给我一个堆栈跟踪,例如

*** First throw call stack:
(0x327453e7 0x3a440963 0x32744ec1 0x330f72c7 0x330f769b 0x330f825b 0x330fa0c7 0x330faefd 0x33103cab 0x3498c519 0x3498d5f1 0x3498d915 0x349920d9 0x34991fe3 0x3268bacd 0x34991f97 0x3268bacd 0x34991f97 0x3268bacd 0x34991f97 0x3268bacd 0x34991f97 0x3268bacd 0x34991f97 0x3268bacd 0x34991f97 0x330fa997 0x3498bf3d 0x345c73dd 0x34303513 0x343030b5 0x34303fd9 0x343039c3 0x343037d5 0x3434a567 0x3a87febb 0x3a87fb93 0x3a898fb8 0x32fe5fc7 0x3305d24f 0x3a88d0e1 0x3a88cfa8)
libc++abi.dylib: terminate called throwing an exception

根据该线程的建议,我实现了自己的未捕获异常处理程序,并打印出以下堆栈跟踪:

    0   CoreFoundation                      0x327453ff <redacted> + 186
1   libobjc.A.dylib                     0x3a440963 objc_exception_throw + 30
2   CoreFoundation                      0x32744ec1 <redacted> + 0
3   Foundation                          0x330f72c7 <redacted> + 422
4   Foundation                          0x330f769b <redacted> + 298
5   Foundation                          0x330f825b <redacted> + 202
6   Foundation                          0x330fa0c7 <redacted> + 242
7   Foundation                          0x330faefd <redacted> + 500
8   Foundation                          0x33103cab <redacted> + 390
9   UIKit                               0x3498c519 <redacted> + 128
10  UIKit                               0x3498d5f1 <redacted> + 196
11  UIKit                               0x3498d915 <redacted> + 88
12  UIKit                               0x349920d9 <redacted> + 84
13  UIKit                               0x34991fe3 <redacted> + 182
14  CoreFoundation                      0x3268bacd CFArrayApplyFunction + 176
15  UIKit                               0x34991f97 <redacted> + 106
16  CoreFoundation                      0x3268bacd CFArrayApplyFunction + 176
17  UIKit                               0x34991f97 <redacted> + 106
18  CoreFoundation                      0x3268bacd CFArrayApplyFunction + 176
19  UIKit                               0x34991f97 <redacted> + 106
20  CoreFoundation                      0x3268bacd CFArrayApplyFunction + 176
21  UIKit                               0x34991f97 <redacted> + 106
22  CoreFoundation                      0x3268bacd CFArrayApplyFunction + 176
23  UIKit                               0x34991f97 <redacted> + 106
24  CoreFoundation                      0x3268bacd CFArrayApplyFunction + 176
25  UIKit                               0x34991f97 <redacted> + 106
26  Foundation                          0x330fa997 <redacted> + 166
27  UIKit                               0x3498bf3d <redacted> + 124
28  UIKit                               0x345c73dd <redacted> + 72
29  QuartzCore                          0x34303513 <redacted> + 214
30  QuartzCore                          0x343030b5 <redacted> + 460
31  QuartzCore                          0x34303fd9 <redacted> + 16
32  QuartzCore                          0x343039c3 <redacted> + 238
33  QuartzCore                          0x343037d5 <redacted> + 316
34  QuartzCore                          0x3434a567 <redacted> + 170
35  libsystem_c.dylib                   0x3a87febb _pthread_tsd_cleanup + 174
36  libsystem_c.dylib                   0x3a87fb93 <redacted> + 118
37  libsystem_c.dylib                   0x3a898fb8 pthread_exit + 27
38  Foundation                          0x32fe5fc7 <redacted> + 10
39  Foundation                          0x3305d24f <redacted> + 1002
40  libsystem_c.dylib                   0x3a88d0e1 <redacted> + 308
41  libsystem_c.dylib                   0x3a88cfa8 thread_start + 8
ios objective-c debugging uicollectionview
1个回答
1
投票

1:当您使用集合视图离开视图控制器时,您是否将集合视图中的委托引用和数据源清零,以便不再被查询?

表视图也会发生这种情况,对象仍然存在,但数据或源不会。

2:我还建议在修改集合时使用@synchronized(self)。这样设置和读取它的代码就不会发生冲突(枚举的崩溃)

© www.soinside.com 2019 - 2024. All rights reserved.