web-dev-qa-db-fra.com

iOS 10 avec XCode 8 GM NSUserDefaults ne fonctionnait pas par intermittence

NOTE: J'ai vu beaucoup d'autres publications sur Stack Overflow à propos de NSUserDefaults en train d'être renommé UserDefaults dans Swift ou ne fonctionnant pas sur le simulateur avant un redémarrage. Ce n'est en aucun cas un doublon. La plupart des questions que SO pose sont d'il y a 4 ans. Ma question concerne spécifiquement iOS 10 à partir de cette année, car elle a toujours fonctionné dans les versions antérieures. J'ai déjà mentionné dans ma question que ma question n'était pas une duplication de ces questions, car il s'agissait de bogues de simulateur dans Swift et que mon problème concernait le bogue Objective C de l'appareil. Veuillez lire les questions avant de marquer comme duplicata

Mon problème est différent car je peux reproduire ceci sur Objective C et sur le périphérique physique lui-même.

J'ai créé un nouveau projet à partir de zéro pour ce test. J'ai placé ce code dans la viewDidLoad d'un contrôleur de vue:

if (![[NSUserDefaults standardUserDefaults] valueForKey:@"checkIfInitialized"]){
    NSLog(@"setting checkIfInitialized as not exist");
    [[NSUserDefaults standardUserDefaults] setValue:@"test" forKey:@"checkIfInitialized"];
    [[NSUserDefaults standardUserDefaults] synchronize];
    self.view.backgroundColor=[UIColor redColor];
    self.mylabel.text=@"NSUserDefaults was NOT there, try running again";
} else {
    NSLog(@"checkIfInitialized exists already");
    self.view.backgroundColor=[UIColor blueColor];
    self.mylabel.text=@"NSUserDefaults was already there this time, try running again";
}

Maintenant, si je lance l'application environ 10 fois, quelques fois, il trouve la checkIfInitialized et parfois non. Aucun nombre exact sur combien de fois il échoue car il pourrait fonctionner 3 fois puis échouer les 2 prochaines fois puis travailler 4 fois et échouer une fois et ainsi de suite. 

Maintenant, quelque chose que j'ai remarqué (pas à 100% si sûr) que le problème ne semble se produire que lorsque je teste connecté via Xcode. Si je lance en lançant l'application en cliquant sur l'icône de l'application sur un périphérique sans Xcode, cela semble fonctionner correctement, mais je ne peux pas être sûr à 100%.

J'ai remarqué que cette erreur se produit parfois:

[User Defaults] Failed to write value for key checkIfInitialized in CFPrefsPlistSource<0x1700f7200> (Domain: com.xxxx.appname, User: kCFPreferencesCurrentUser, ByHost: No, Container: (null)): Path not accessible, switching to read-only

J'ai ce projet très simple sur ma boîte de dépôt si vous voulez le tester. Je suggérerais de tester environ 10-15 fois pour reproduire ce problème.

https://www.dropbox.com/s/j7vbgl6e15s57ix/nsuserdefaultbug.zip?dl=0

Cela fonctionne parfaitement sur iOS 9, donc il y a certainement quelque chose à voir avec iOS 10.

MODIFIERBug enregistré: 28287988

Réponse de Apple DTS team:

Tout d’abord, vous devez d’abord déterminer si standardUserDefaults ou ValueForKey échoue. J’imagine que «standardUserDefaults» renvoie Et renvoie NULL. Si tel est le cas, vous devriez vous en prémunir contre cela. En particulier, standardUserDefaults Renvoie la valeur NULL si le fichier de préférences est chiffré dans l'environnement Dans lequel l'application est en cours d'exécution (par exemple, les préférences Sont définies sur «NSFileProtectionComplete» et l'application s'exécute dans le fond ). Cela ne devrait pas poser de problème pour les applications standard de premier plan Uniquement, mais il faut en être conscient.

Il est très probable que Xcode provoque le problème ici. Xcode complique considérablement l’environnement de lancement des applications d’une manière qui Est TRÈS différente du lancement d’une application standard. Mon hypothèse est que cela est Essentiellement déclenché par le minutage de Xcode qui induit une situation attendue Lors du lancement de l'application, mais si vous souhaitez un test plus formel de , Essayez de définir une point d'arrêt unique dans applicationDidFinishLaunching et continuer dans le débogueur dès que vous l'avez atteint. Je suppose que Ajoute simplement que cela perturbe suffisamment le timing pour que le problème ne se produise plus. Sorte de. C'est iOS 10 uniquement dans le sens où iOS 9 N'imprimera jamais ce message de journal, mais c'est parce que le message de journal a été ajouté dans iOS 10. Le code lui-même est suffisamment similaire à iOS 9.3 pour que je soupçonne que le même comportement est (du moins en théorie) possible dans iOS 9.

17
Pranoy C

Oui, c’est vraiment un bug reproductible. 

  • Cela se produit avec la version GM de Xcode 8 et iOS 10.
  • C'est not la question liée se rapportant à Swift.
  • C'est not la question liée se rapportant aux versions bêta du simulateur.

Le bogue survient sur les appareils et sur le simulateur. C'est intermittent: économiser fonctionnera six fois puis échouera. Contrairement à vous, je n'ai pas reçu le message "Impossible d'écrire la clé".

Le bogue survient également lorsque vous travaillez directement sur le périphérique sans Xcode. C'est en fait comment je l'ai découvert.

Vous devriez signaler un bogue à Apple , surtout que vous avez un programme court qui va le reproduire. Je vais faire la même chose.

Une différence clé: Dans mon cas, l'échec est dans écriture par défaut. La valeur précédemment écrite reste dans NSUserDefaults. Parfois, une clé est écrite avec succès tandis que l’autre est inchangée. 

9
nugae

DTS réponse similaire très intelligente de ma propre demande d'assistance. Tuer à l'aide de Xcode est plus meurtrier que tout ce qui se produirait naturellement sur l'appareil (même la méthode du double clic clic-et-relance): comme tout est brusquement écrasé lorsque Xcode l'arrête, l'écriture paresseuse de NSUserDefaults peut échouer, ou être seulement à moitié terminé.

Et en effet, des tests purement sur l'appareil de l'application, sans Xcode, montrent que tout est correctement écrit sur NSUserDefaults lorsque l'application est fermée.

J'ai fermé mon propre rapport de bogue.

0
nugae