我现在已经坚持了一个多星期了,显然没有人在stackoverflow之前报告过这个问题。在将我介绍给其他帖子之前,请仔细阅读我的说明,因为我已经阅读了所有帖子,但没有一个人有我的答案。
我有一个NSDictionary包含NSNumber和NSStrings的NSArray,两个键都是NSStrings。
现在NSDictionary writeToFile崩溃并出现错误: - [ NSDictionaryI isNSString ]:发送到解除分配的实例的消息
在类方法上调用writeToFile:
@implementation AppDataStore
+ (void) saveData:(NSDictionary*)dataDictionary {
NSArray *directories = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documents = [directories firstObject];
NSString *appDataFilePath = [documents stringByAppendingPathComponent:@"AppDataStore.plist"];
[dataDictionary writeToFile:appDataFilePath atomically:YES];
}
值得注意的是,我正在向该方法传递一个NSMutableDictionary,但这不是问题,因为它写的其他键值NSMutableDictionaries就好了,但不包含这个和NSArray的那个。即使我拿出NSNumber元素,因此字典只包含一个NSArray,writeToFile仍然会崩溃同样的错误。在模拟器和iPhone上崩溃。
发生了什么事?!
编辑1(回应亚当的问题):
直到崩溃前的堆栈跟踪:
Stack trace : (
0 MedList 0x00009b39 +[AppDataStore saveData:] + 217
1 MedList 0x0000811d -[ViewController tableView:didSelectRowAtIndexPath:] + 1101
2 UIKit 0x010c894c -[UITableView _selectRowAtIndexPath:animated:scrollPosition:notifyDelegate:] + 1559
3 UIKit 0x010c8af7 -[UITableView _userSelectRowAtPendingSelectionIndexPath:] + 285
4 UIKit 0x010cddf3 __38-[UITableView touchesEnded:withEvent:]_block_invoke + 43
5 UIKit 0x00fe20ce ___afterCACommitHandler_block_invoke + 15
6 UIKit 0x00fe2079 _applyBlockToCFArrayCopiedToStack + 415
7 UIKit 0x00fe1e8e _afterCACommitHandler + 545
8 CoreFoundation 0x00b289de __CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__ + 30
9 CoreFoundation 0x00b28920 __CFRunLoopDoObservers + 400
10 CoreFoundation 0x00b1e35a __CFRunLoopRun + 1226
11 CoreFoundation 0x00b1dbcb CFRunLoopRunSpecific + 443
12 CoreFoundation 0x00b1d9fb CFRunLoopRunInMode + 123
13 GraphicsServices 0x03efd24f GSEventRunModal + 192
14 GraphicsServices 0x03efd08c GSEventRun + 104
15 UIKit 0x00fb88b6 UIApplicationMain + 1526
16 MedList 0x0000681d main + 141
17 libdyld.dylib 0x02f6bac9 start + 1
18 ??? 0x00000001 0x0 + 1
)
2015-02-16 21:39:37.762 MedList[14029:496685] *** -[__NSDictionaryI isNSString__]: message sent to deallocated instance 0x7974e910
编辑2:我做了一些测试。我的NSArray中的NSDictionary在类方法调用之前(在writeToFile之前)和仅在AFTER didSelectRowAtIndexPath之前被释放。为什么选择表行会自动释放数组中包含的字典?这是奇怪的行为。有什么想法吗?
答案 0 :(得分:0)
writeToFile:atomically:
及其亲属都要求整个"对象图"你写作必须是"属性列表"对象(一小类类:NSString,NSData,NSDate,NSNumber,NSArray或NSDictionary)。任何对象图中任何容器或子容器中没有对象的对象都会导致写入失败。
但是,我以前看到的只是没有写入文件,而不是崩溃。你可能在你的阵列中的某个地方有一个僵尸,尽管在ARC下它比在手动引用计数下更不可能。您必须将__unsafe_unretained对象添加到数组或数组内的容器。
答案 1 :(得分:0)
首先,谢谢大家,特别是Duncan和Hot Licks,帮助我缩小bug并最终捕获它。所以,我注意到,当我离开viewDidLoad的范围时,我的NSArray中的NSDictionary被释放,这意味着我实际上并没有拥有那个NSDictionary,尽管我以为我做了。
问题是由于我通过另一个类方法调用创建了NSDictionary,我天真地命名为init,因此隐瞒了我对返回的NSDictionary的实际非所有权,愚弄我以为我只是通过调用init来拥有它。
在我将init重命名为“create”之后问题解决了,然后在调用create之前在我的viewDidLoad中正确地分配了我的NSDictionary。现在保留了字典,错误消失了。
对于那些面临类似问题的人,我强烈推荐这个资源,这实际上让我最终找到了这个错误:
https://developer.apple.com/library/ios/documentation/Cocoa/Conceptual/MemoryMgmt/MemoryMgmt.pdf