由于我们将类名从Bestemming更改为Place,并将其从Objective-C重写为Swift,一些用户在使用它时会遇到崩溃。我们试图使用NSCoding原则从NSUserDefaults中加载对象。
崩溃信息:
Thread : Crashed: com.apple.main-thread
0 Flitsmeister 0x10018b720 specialized Place.init(coder : NSCoder) -> Place? (Place.swift)
1 Flitsmeister 0x10018a6f4 @objc Place.init(coder : NSCoder) -> Place? (Place.swift)
2 Foundation 0x1839ab92c _decodeObjectBinary + 2276
3 Foundation 0x1839aaf90 _decodeObject + 304
4 Foundation 0x1839aa124 +[NSKeyedUnarchiver unarchiveObjectWithData:] + 92
5 Flitsmeister 0x100103fa0 +[SharedUserDefaultsManager WorkPlace] (SharedUserDefaultsManager.m:72)
6 Flitsmeister 0x100090830 -[InvoerBestemmingTableViewController viewWillAppear:] (InvoerBestemmingTableViewController.m:106)
7 UIKit 0x187d8074c -[UIViewController _setViewAppearState:isAnimating:] + 628
8 UIKit 0x187d804c0 -[UIViewController __viewWillAppear:] + 156
9 UIKit 0x187e27130 -[UINavigationController _startTransition:fromViewController:toViewController:] + 760
10 UIKit 0x187e26a6c -[UINavigationController _startDeferredTransitionIfNeeded:] + 868
11 UIKit 0x187e26694 -[UINavigationController __viewWillLayoutSubviews] + 60
12 UIKit 0x187e265fc -[UILayoutContainerView layoutSubviews] + 208
13 UIKit 0x187d63778 -[UIView(CALayerDelegate) layoutSublayersOfLayer:] + 656
14 QuartzCore 0x185772b2c -[CALayer layoutSublayers] + 148
15 QuartzCore 0x18576d738 CA::Layer::layout_if_needed(CA::Transaction*) + 292
16 QuartzCore 0x18576d5f8 CA::Layer::layout_and_display_if_needed(CA::Transaction*) + 32
17 QuartzCore 0x18576cc94 CA::Context::commit_transaction(CA::Transaction*) + 252
18 QuartzCore 0x18576c9dc CA::Transaction::commit() + 512
19 UIKit 0x187d59c78 _afterCACommitHandler + 180
20 CoreFoundation 0x18302c588 __CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__ + 32
21 CoreFoundation 0x18302a32c __CFRunLoopDoObservers + 372
这个类:
@objc(Place)
class Place : NSObject, NSCoding, CustomDebugStringConvertible
{
let name: String
let location: CLLocation
var lastUsed: NSDate?
var type: PlaceType
var address: String?
//MARK: - NSCoding protocol
func encodeWithCoder(aCoder: NSCoder) {
aCoder.encodeObject(name, forKey: "name")
aCoder.encodeObject(address, forKey: "address")
aCoder.encodeInt(type.rawValue, forKey: "type")
aCoder.encodeObject(location, forKey: "location")
aCoder.encodeObject(lastUsed, forKey: "lastUsed")
}
required init?(coder aDecoder: NSCoder) {
if let locatieNaam : String = aDecoder.decodeObjectForKey("locatieNaam") as? String {
//This is the OLD object
name = locatieNaam
let nullableLocation : CLLocation? = aDecoder.decodeObjectForKey("locatie") as? CLLocation
if let notnulllablelocation : CLLocation = nullableLocation {
location = notnulllablelocation
} else {
location = CLLocation.init(latitude: 0, longitude: 0) //Not possible
}
lastUsed = aDecoder.decodeObjectForKey("lastUsed") as? NSDate
if aDecoder.decodeBoolForKey("isThuis") {
type = .Home
} else if aDecoder.decodeBoolForKey("isWerk") {
type = .Work
} else if aDecoder.decodeBoolForKey("isFavoriet") {
type = .Favoriet
} else {
type = .Other
}
address = nil
}
else {
name = aDecoder.decodeObjectForKey("name") as! String
let nullableLocation : CLLocation? = aDecoder.decodeObjectForKey("location") as? CLLocation
if let notnullableLocation : CLLocation = nullableLocation {
location = notnullableLocation
} else {
location = CLLocation.init(latitude: 0, longitude: 0) //Not possible
}
lastUsed = aDecoder.decodeObjectForKey("lastUsed") as? NSDate
type = PlaceType.init(rawValue: aDecoder.decodeInt32ForKey("type"))!
address = aDecoder.decodeObjectForKey("address") as? String
}
}
}
从NSUserDefaults中读取数据:
+ (Place*)WorkPlace;
{
@try {
NSUserDefaults *mySharedDefaults = [[NSUserDefaults alloc] initWithSuiteName:kSharedUserDefaults];
NSData *result = [mySharedDefaults objectForKey:kWerkBestemming];
if(result == NULL)
return nil;
[NSKeyedUnarchiver setClass:[Place class] forClassName:@"Bestemming"];
[NSKeyedUnarchiver setClass:[Place class] forClassName:@"BestemmingBase"];
Place *place = [NSKeyedUnarchiver unarchiveObjectWithData:result];
if(place != nil) {
place.type = PlaceTypeWork; //Needed because the old Bestemming class didnt saved the boolean isWerk
}
return place;
}
@catch (NSException *exception) {
return nil;
}
}
崩溃日志显示它在第0行崩溃,这是注释,所以我认为它在init方法中崩溃,我认为它与一个对象有关,该对象为空但不能为空。
我尝试过:
- 在SharedUserDefaultsManager中使用try catch
- 对非空项进行额外检查
对于那些应用程序崩溃的用户,我可以从NSUserDefaults中删除该对象。只有当我知道发生这种情况时才能实现。