2016-07-06 6 views
0

Unter dem iOS-Simulator habe ich Probleme beim Abrufen eines konsistenten Werts von NSUserDefault beim Start der Anwendung. Ich habe den Wert in einem vorherigen Lauf der App festgelegt (und ich habe einige Ausdrucke darin eingefügt, um sicherzustellen, dass es keine zufälligen Änderungen gab), also glaube ich nicht, dass es ein Problem mit der Art gibt, wie ich synchronisiere() . Die Lesevorgänge finden auch im Hauptthread statt und nachdem ich die Standardwerte eingestellt habe. Nach ein paar Sekunden, wenn ich den Abruf von NSUserDefaults wiederhole, erhalte ich den richtigen Wert (ich habe einen Timer eingebaut, um zu verifizieren, dass der Wert korrigiert wird und nach dem Start scheinbar gleich bleibt).Inkonsistenter Wert von NSUserDefaults beim Start der App

Der Wert gibt an, wo der Benutzer die Daten speichert (in iCloud oder nur auf dem lokalen Gerät) und wird in den Benutzervorgaben durch eine Ganzzahl dargestellt. Hier ist die Enum die Werte darstellen:

class MovingDocument: UIDocument { 
    enum StorageSettingsState: Int { 
     case NoChoice = 0 
     case Local = 1 
     case ICloud = 2 
    } 
} 

Hier ist ein Auszug aus der Klasse Zugriff NSUserDefaults verwendet:

class Settings { 
    static let global = Settings() 

    private enum LocalStoreKeys : String { 
     case IsHorizontal = "IsHorizontal" 
     case ItemInPortrait = "ItemInPortrait" 
     case RotateTitle = "RotateTitle" 
     case StorageLocation = "StorageLocation" 
    } 

    // Other computed variables here for the other settings. 

    // Computed variable for the storage setting. 
    var storageLocation: MovingDocument.StorageSettingsState { 
     get { 
      print("Storage state fetch: \(NSUserDefaults.standardUserDefaults().integerForKey(LocalStoreKeys.StorageLocation.rawValue))") 
      return MovingDocument.StorageSettingsState(rawValue: NSUserDefaults.standardUserDefaults().integerForKey(LocalStoreKeys.StorageLocation.rawValue)) ?? .NoChoice 
     } 
     set { 
      print("Setting storage location to \(newValue) (\(newValue.rawValue))") 
      NSUserDefaults.standardUserDefaults().setInteger(newValue.rawValue, forKey: LocalStoreKeys.StorageLocation.rawValue) 
      synchronize() 
      CollectionDocument.settingsChanged() 
     } 
    } 

    func prepDefaultValues() { 
     NSUserDefaults.standardUserDefaults().registerDefaults([ 
      LocalStoreKeys.IsHorizontal.rawValue: true, 
      LocalStoreKeys.ItemInPortrait.rawValue: true, 
      LocalStoreKeys.RotateTitle.rawValue: true, 
      LocalStoreKeys.StorageLocation.rawValue: MovingDocument.StorageSettingsState.NoChoice.rawValue 
      ]) 
    } 

    func synchronize() { 
     NSUserDefaults.standardUserDefaults().synchronize() 
    } 
} 

Der Wert, den wir lesen werden sollen (und die ich scheine immer nach dem Start zu bekommen) ist der Wert '1' oder .Lokal. Der Wert, den ich manchmal bekomme, ist '0' oder .NoChoice (was zufällig der Standardwert ist). Es sieht also so aus, als ob der Standardwert bis zu einem späteren Zeitpunkt beim Start der Anwendung verwendet wird.

Der Vollständigkeit halber ist hier die entsprechenden AppDelegate Code:

func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool { 
    // Override point for customization after application launch. 

    Settings.global.prepDefaultValues() // Must be called before doing CollectionDocument.start() because we need the default value for storage location. 
    CollectionDocument.start() 
    self.window = UIWindow(frame: UIScreen.mainScreen().bounds) 
    browserController = ViewController() 
    navController = UINavigationController(rootViewController: browserController!) 
    navController!.navigationBar.translucent = false 
    self.window!.rootViewController = navController 
    self.window!.makeKeyAndVisible() 
    checkStorageLocation() 
    return true 
} 

Der Getter innerhalb CollectionDocument.start() aufgerufen wird (CollectionDocument ist eine Unterklasse von MovingDocument, wo die Lage Enum definiert ist). Der Aufruf am Ende von checkStorageLocation() ist meine periodische Debugging-Prüfung auf den Wert des Speicherplatzes (er ruft sich selbst via dispatch_after() zurück).

Als Nebenbemerkung habe ich auch versucht, den Großteil des Codes in der Anwendung (didFinishLaunchingWithOptions ...) in einen Dispatch_async-Aufruf (auf dem Haupt-Thread) zu setzen, um zu sehen, ob das einen Unterschied machte (nur der Aufruf zum Einrichten die Standardwerte und die return-Anweisung wurden sofort ausgeführt, der Rest der Aufrufe wurde in den asynchronen Aufrufblock geschrieben) und hat (manchmal) immer noch den falschen Wert. Ich könnte versuchen, dispatch_after stattdessen zu verwenden (und ein oder zwei Sekunden warten), aber ich kann die App nicht wirklich starten, bis dies abgeschlossen ist (weil ich die Benutzerdaten aus dem Dokument nicht lesen kann, bis ich weiß, wo es ist) und ein Ladebildschirm für genau dieses eine Problem erscheint lächerlich.

Irgendwelche Ideen über was könnte schief gehen? Ich kenne keine Einschränkungen von NSUserDefaults soweit, wenn Sie von ihm lesen dürfen ...

+0

Das passiert übrigens mit Xcode Version 7.3.1, iOS Version 9.3 im iPhone 4s Simulator. –

+0

Zunächst müssen Sie 'synchronize' nicht aufrufen. Zweitens, warum verwenden Sie' registerDefaults' jedes Mal, wenn Ihre App läuft? Dies überschreibt die aktuellen Werte. – Paulw11

+0

Obwohl eine Synchronisierung normalerweise nicht erforderlich ist, wollte ich, dass der Wert beibehalten wird, bevor ich anfange, darauf zu reagieren (es kann ein paar Sekunden dauern, bis die Benutzerwerte ausgegeben werden, zu welchem ​​Zeitpunkt das Dokument erstellt worden wäre) genannt) oder verschoben (wenn sie sich später dazu entschließen, das Dokument zu verschieben), nur für diese bestimmte Einstellung sicher sein (der Rest verwendet das Lazy Update). Wie bei registerDefaults sollte das jedes Mal aufgerufen werden, wenn die App gestartet wird docs (und meine vorherige Verwendung). Es füllt nur Löcher, es soll keine tatsächlichen Schreibvorgänge überschreiben. –

Antwort

1

Neustart meines Mac behoben das Problem (was auch immer es war). iOS 10, NSUserDefaults Does Not Work hat ein ähnliches Problem und die gleiche Lösung (obwohl die Umstände ganz anders sind, da ich weder Xcode 8 noch iOS 10 ausprobiert habe).