使用NSKeyedArchiver压缩对象成二进制数据,再使用NSKeyedUnarchiver解压二进制数据,如果解压时数据为nil,或者数据中有异常的数据,那么解压将会出错,甚至会导致程序crash掉,例如报错如下:
*** Terminating app due to uncaught exception 'NSRangeException', reason: '*** -[__NSArrayM objectAtIndex:]: index 0 beyond bounds for empty array'
*** First throw call stack:
(
0 CoreFoundation 0x026ca5e4 __exceptionPreprocess + 180
1 libobjc.A.dylib 0x023988b6 objc_exception_throw + 44
2 CoreFoundation 0x0266b556 -[__NSArrayM objectAtIndex:] + 246
3 论文批阅系统 0x0002b2f0 -[Stroke initWithCoder:] + 320
4 Foundation 0x01fabd6a _decodeObjectBinary + 3498
5 Foundation 0x01fad226 -[NSKeyedUnarchiver _decodeArrayOfObjectsForKey:] + 2204
6 Foundation 0x01fad495 -[NSArray(NSArray) initWithCoder:] + 255
7 Foundation 0x01fabd6a _decodeObjectBinary + 3498
8 Foundation 0x01faae55 _decodeObject + 340
9 Foundation 0x01faacf9 -[NSKeyedUnarchiver decodeObjectForKey:] + 181
10 Foundation 0x0201c8cd +[NSKeyedUnarchiver unarchiveObjectWithData:] + 106
11 论文批阅系统 0x0001b057 -[MyPDFPage initWithDocument:PageIndex:] + 3223
12 论文批阅系统 0x0002c1b8 -[PDFScrollView initWithFrame:Document:PageIndex:] + 856
13 论文批阅系统 0x00022ae9 -[MainPDFViewController viewDidLoad] + 5193
14 UIKit 0x0121e9a8 -[UIViewController loadViewIfRequired] + 696
15 UIKit 0x0121ec44 -[UIViewController view] + 35
16 UIKit 0x01238a72 -[UINavigationController _startCustomTransition:] + 778
17 UIKit 0x01245757 -[UINavigationController _startDeferredTransitionIfNeeded:] + 688
18 UIKit 0x01246349 -[UINavigationController __viewWillLayoutSubviews] + 57
19 UIKit 0x0137f39d -[UILayoutContainerView layoutSubviews] + 213
20 UIKit 0x01175dd7 -[UIView(CALayerDelegate) layoutSublayersOfLayer:] + 355
21 libobjc.A.dylib 0x023aa81f -[NSObject performSelector:withObject:] + 70
22 QuartzCore 0x00dd872a -[CALayer layoutSublayers] + 148
23 QuartzCore 0x00dcc514 _ZN2CA5Layer16layout_if_neededEPNS_11TransactionE + 380
24 QuartzCore 0x00dcc380 _ZN2CA5Layer28layout_and_display_if_neededEPNS_11TransactionE + 26
25 QuartzCore 0x00d34156 _ZN2CA7Context18commit_transactionEPNS_11TransactionE + 294
26 QuartzCore 0x00d354e1 _ZN2CA11Transaction6commitEv + 393
27 QuartzCore 0x00d35bb4 _ZN2CA11Transaction17observer_callbackEP19__CFRunLoopObservermPv + 92
28 CoreFoundation 0x0269253e __CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__ + 30
29 CoreFoundation 0x0269248f __CFRunLoopDoObservers + 399
30 CoreFoundation 0x026703b4 __CFRunLoopRun + 1076
31 CoreFoundation 0x0266fb33 CFRunLoopRunSpecific + 467
32 CoreFoundation 0x0266f94b CFRunLoopRunInMode + 123
33 GraphicsServices 0x0343d9d7 GSEventRunModal + 192
34 GraphicsServices 0x0343d7fe GSEventRun + 104
35 UIKit 0x0110b94b UIApplicationMain + 1225
36 论文批阅系统 0x0002b17d main + 141
37 libdyld.dylib 0x0676b70d start + 1
)
libc++abi.dylib: terminating with uncaught exception of type NSException
在苹果官网上找到了一个防止crash的方法(http://lists.apple.com/archives/cocoa-dev/2009/Jul/msg00181.html),就是使用try - catch - finally语句块:
例如,将
// 解压从文件中加载的二进制数据
NSMutableData *mdata = [filePersistence loadMutableDataFromFile:drawStrokesFileName inDocumentWithDirectory:drawStrokesFileDirectory];
if (mdata) {
self.previousDrawStrokes = [NSKeyedUnarchiver unarchiveObjectWithData:mdata];
}
更改为:
NSMutableData *mdata = [filePersistence loadMutableDataFromFile:drawStrokesFileName inDocumentWithDirectory:drawStrokesFileDirectory];
if (mdata) {
@try {
self.previousDrawStrokes = [NSKeyedUnarchiver unarchiveObjectWithData:mdata];
}
@catch (NSException *exception) {
NSLog(@"%@", exception);
}
@finally {
}
}
再运行,尽管程序依然会报错:
2013-11-29 18:40:33.820 论文批阅系统[3073:70b] *** -[__NSArrayM objectAtIndex:]: index 0 beyond bounds for empty array
但起码不会crash掉。
但要注意的是,这个方法只是防止程序崩溃(起码程序不会死掉了),并没有从根本上解决错误。