2016-03-21 5 views
6

Da wir die Klasse umbenannt (Bessteming -> Place) und von Objective-C in Swift umgeschrieben haben, stürzen einige User ab. Wir versuchen, ein Objekt aus den NSUserDefaults mit dem NSCoding-Prinzip zu laden.Absturz beim Dekodieren des Objekts nach dem Umbenennen und Umschreiben nach Swift

Der Absturz:

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 

Die Klasse:

@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 
     } 
    } 
} 

von NSUserDefaults Lesen:

+ (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; 
    } 
} 

Der Crash-Protokoll heißt es auf Linie abstürzt 0, der Kommentar, so ist I denke, dass es in der init-Methode abstürzt und ich denke, dass es etwas mit einem Objekt zu tun hat, das null ist, aber nicht null sein kann.

was ich versucht habe:

  • Try catch in SharedUserDefaultsManager
  • Zusätzliche Kontrollen auf nicht-nullables

Für Anwender, wo die App abstürzt ich mit dem Entfernen des Objekts leben können aus NSUserDefaults. Nur wenn ich wissen kann, wann es passiert.

+0

Wie ein Kommentar versuchen Sie, If (Ergebnis == Nil) anstatt NULL zu vergleichen. Haben Sie versucht zu debuggen, was aDecoder.decodeObjectForKey ("locatieNaam") zurückgibt? Korrigiere mich, wenn ich auf die falsche Linie des Absturzes schaue. –

+0

Nun, ich kann es nicht reproduzieren :(Auch ich weiß nicht, welche Zeile der Absturz ist, weil crashlog sagt linenumber Null –

+0

Können Sie Ihren Code zu neuesten Commit vor Swift-Klasse, speichern ObjC Objekt auf Festplatte und dann Check-to neuesten Swift-Code und Erstelle den Absturz? –

Antwort

0

Denken dies ein viel besserer Ansatz ist mit dem NSCoding init-Methode zu behandeln und das Rück nil, wenn Variablen sind nicht das, was Sie erwarten:

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") 
    ) 
} 

Von NSHipster: http://nshipster.com/nscoding/

Nun wollen wir sehen, wie die Neue Version funktioniert.

Edit: es hat funktioniert!

Verwandte Themen