NSArray 深拷贝导致崩溃
我已经盯着这段代码有一段时间了,但无法弄清楚到底出了什么问题。我有一个名为 SortFilteringController 的类,它管理系统中的不同过滤(内部过滤器、公共过滤器、排序选项等)。其中每一个都存储在一个数组中。所以我有一个方便的方法,它基本上采用这些数组中的任何一个,并用一些新数据重置它们。
例如setInternalFilter,只需调用它即可。
- (void) setInternalFilterTerms : (NSArray*) filterTerms {
[self resetArray: &_internalFilters withNewData:filterTerms];
}
ResetArray的定义,只是转储现有的(释放它),并复制新的数据。
- (void) resetArray: (NSMutableArray**) oldArray withNewData : (NSArray*) newData {
if (*oldArray != nil) {
[*oldArray release];
}
NSMutableArray* newArray = [[NSMutableArray alloc] initWithArray:newData copyItems:YES];
*oldArray = [newArray retain];
[newArray release];
}
但我的问题是我在重置方法中遇到了崩溃。不在模拟器中,仅在设备上。
Thread 0 Crashed:
0 libsystem_kernel.dylib 0x331a3a1c __pthread_kill + 8
1 libsystem_c.dylib 0x3404c3b4 pthread_kill + 52
2 libsystem_c.dylib 0x34044bf8 abort + 72
3 libstdc++.6.dylib 0x30e4fa64 __gnu_cxx::__verbose_terminate_handler() + 376
4 libobjc.A.dylib 0x30fda06c _objc_terminate + 104
5 libstdc++.6.dylib 0x30e4de36 __cxxabiv1::__terminate(void (*)()) + 46
6 libstdc++.6.dylib 0x30e4de8a std::terminate() + 10
7 libstdc++.6.dylib 0x30e4df5a __cxa_throw + 78
8 libobjc.A.dylib 0x30fd8c84 objc_exception_throw + 64
9 CoreFoundation 0x33e5f1b8 -[NSObject(NSObject) doesNotRecognizeSelector:] + 96
10 CoreFoundation 0x33e5e642 ___forwarding___ + 502
11 CoreFoundation 0x33dd5178 _CF_forwarding_prep_0 + 40
12 CoreFoundation 0x33dcb156 -[NSArray initWithArray:range:copyItems:] + 366
13 CoreFoundation 0x33dcafce -[NSArray initWithArray:copyItems:] + 54
14 Wine DB 1.1 0x001b6a2a -[SortFilterController resetArray:withNewData:] (SortFilterController.m:1310)
15 Wine DB 1.1 0x001b4188 -[SortFilterController setInternalFilterTerms:] (SortFilterController.m:733)
我正在运行 xcode 4.2 和 iOS 5.0 GM 种子。我的设备仍在运行 4.1.3。但这应该不会有什么不同吧?错误是“doesNotRecognizeSelector”。多么奇怪啊。
谢谢。
I've been staring at this code for a while now, but can't figure out what in the world is wrong. I have a class called SortFilteringController, which manages the different filtering that I have in the system (internal filter, public filter, sort options, etc). Each of these is stored in an array. So I have a convience method, which basically takes any of these arrays, and resets them with some new data.
For example, the setInternalFilter, just calls it.
- (void) setInternalFilterTerms : (NSArray*) filterTerms {
[self resetArray: &_internalFilters withNewData:filterTerms];
}
The definition of resetArray, is just to dump the existing one (release it), and copy the new data across.
- (void) resetArray: (NSMutableArray**) oldArray withNewData : (NSArray*) newData {
if (*oldArray != nil) {
[*oldArray release];
}
NSMutableArray* newArray = [[NSMutableArray alloc] initWithArray:newData copyItems:YES];
*oldArray = [newArray retain];
[newArray release];
}
But my problem is I get a crash in the reset method. Not in the simulator, only on the device.
Thread 0 Crashed:
0 libsystem_kernel.dylib 0x331a3a1c __pthread_kill + 8
1 libsystem_c.dylib 0x3404c3b4 pthread_kill + 52
2 libsystem_c.dylib 0x34044bf8 abort + 72
3 libstdc++.6.dylib 0x30e4fa64 __gnu_cxx::__verbose_terminate_handler() + 376
4 libobjc.A.dylib 0x30fda06c _objc_terminate + 104
5 libstdc++.6.dylib 0x30e4de36 __cxxabiv1::__terminate(void (*)()) + 46
6 libstdc++.6.dylib 0x30e4de8a std::terminate() + 10
7 libstdc++.6.dylib 0x30e4df5a __cxa_throw + 78
8 libobjc.A.dylib 0x30fd8c84 objc_exception_throw + 64
9 CoreFoundation 0x33e5f1b8 -[NSObject(NSObject) doesNotRecognizeSelector:] + 96
10 CoreFoundation 0x33e5e642 ___forwarding___ + 502
11 CoreFoundation 0x33dd5178 _CF_forwarding_prep_0 + 40
12 CoreFoundation 0x33dcb156 -[NSArray initWithArray:range:copyItems:] + 366
13 CoreFoundation 0x33dcafce -[NSArray initWithArray:copyItems:] + 54
14 Wine DB 1.1 0x001b6a2a -[SortFilterController resetArray:withNewData:] (SortFilterController.m:1310)
15 Wine DB 1.1 0x001b4188 -[SortFilterController setInternalFilterTerms:] (SortFilterController.m:733)
I am running xcode 4.2 with iOS 5.0 GM seed. My device is still running 4.1.3. But that shouldn't make a difference right? And the error is "doesNotRecognizeSelector". How strange is that.
Thanks.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
检查oldArray == newData 是否。您会注意到 Objective-C 中设置操作的默认习惯用法是这样的:
如果 newThing == thing,并且您删除了当前的 thing,那么您很可能会导致它调用其析构函数。所以你总是先做保留。
因此,您有可能释放您想要复制的对象。而且,使用最新、最好的垃圾收集器,设备的清理速度可能比模拟器更快。两个平台上都存在错误,但内存管理器的不确定性可能会让您认为它是暂时的。
如果没有别的事,请检查您的代码以确保您没有释放稍后可能需要在函数中使用的对象。仅仅因为变量名称不同,并不意味着它们不是同一个对象。
Check to see if oldArray == newData. You'll notice that the default idiom for a set operation in Objective-C is this:
If newThing == thing, and you delete the current thing, then you may well cause it to call its destructor. So you always do the retain first.
So it's possible your releasing the very objects you want to copy. And, using the latest-and-greatest garbage collectors, the device may be cleaning up faster than the simulator. The bugs is there on both platforms, but the indeterminate nature of the memory manager can make you think it's transient.
If nothing else, review your code to make sure you're not releasing objects you might need to be using later in the function. Just because the variable names are different, it doesn't mean they aren't the same object.
难道数组中存储的对象不符合 NSCopying 协议吗?因此,当初始化程序尝试对其调用
copy
方法时,他们只是不知道如何处理它?Could it be that come of the objects stored in an array does not conform to
NSCopying
protocol? So when initializer tries to callcopy
method on them they just don't know how to handle it?