由于我们已经重命名了(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方法中崩溃,我认为它与一个null为空但不能为null的对象有关.
我尝试过的:
>尝试在SharedUserDefaultsManager中捕获
>对非空缺的额外检查
对于应用程序崩溃的用户,我可以使用从NSUserDefaults中删除对象.只有我知道它何时发生.
解决方法
认为这是处理NSCoding init方法的更好方法,如果变量不是您所期望的,则返回nil:
required convenience init?(coder decoder: NSCoder) { guard let title = decoder.decodeObjectForKey("title") as? String,let author = decoder.decodeObjectForKey("author") as? String,let categories = decoder.decodeObjectForKey("categories") as? [String] else { return nil } self.init( title: title,author: author,pageCount: decoder.decodeIntegerForKey("pageCount"),categories: categories,available: decoder.decodeBoolForKey("available") ) }
来自NSHipster:http://nshipster.com/nscoding/
现在让我们看看新版本是如何运作的.
编辑:它奏效了!