Since we renamed the (Bestemming β Place) class and rewrote it from Objective-c to Swift, some users came across it. We are trying to load an object from NSUserDefaults using the NSCoding principle.
Accident:
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
Grade:
@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 } } }
Reading from 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;
The crash log says it is crashing on line 0, which is a comment, so I think it is crashing in the init method, and I think it has something to do with an object that is null but cannot be null .
What I tried:
- Try to catch in SharedUserDefaultsManager
- Additional non-nullables checks
For those users where the application crashes, I can live with the removal of the object from NSUserDefaults. Only if I know when this will happen.
source share