NSKeyedUnarchiver-essai / capture nécessaire?

comme je le comprends, l'utilisation des blocs @try/@catch est déconseillée, parce que exceptions devrait seulement être jeté à des erreurs irrécupérables, catastrophiques (se référer à cette discussion avec une belle réponse par @bbum : Exception Handeling in iOS ).

alors j'ai regardé mon code et j'ai trouvé un bloc @try/@catch dont je ne sais pas comment me débarrasser:

NSData *fileData = [NSData dataWithContentsOfFile: ....];

NSDictionary *dictionary;

@try {
   dictionary = [NSKeyedUnarchiver unarchiveObjectWithData: fileData];
}
@catch (NSException *exception) {
   //....
}
@finally {
  //...
}

le problème est que (comme indiqué dans la documentation ) +unarchiveObjectWithData: soulève un NSInvalidArchiveOperationException si le NSData ne contient pas une archive valide.

, Puisque les données sont fournies par un fichier que l'utilisateur a choisi, il n'est pas garanti qu'il contient une archive valide, et donc l'application plante si un fichier incorrecte a été choisi.

maintenant deux questions:

  1. Pourquoi ne pas +unarchiveObjectWithData: juste retour nil ( éditer: et un NSError** ) si l'archive n'est pas valide (cela ne semble pas qualifier comme une erreur catastrophique ou irrécupérable).
  2. le schéma ci-dessus est-il correct (en utilisant @try )? Je n'ai trouvé aucune méthode nous permettant de vérifier si les données contiennent une archive valide au préalable et n'ai trouvé aucune possibilité de gérer ce cas en utilisant le protocole delegate. Antyhing que j'ai négligé?

noter que le code ci-dessus de cours de travaux, je me demande juste si c'est la meilleure pratique.

20
demandé sur Community 2013-06-25 18:01:53
la source

2 ответов

NSKeyedArchiver est construit par Apple. Ils contrôlent le code qui est exécuté pendant que unarchiveObjectWithData: exécute de sorte qu'ils contrôlent également la gestion des ressources pendant le traitement des exceptions (qui est la source des problèmes derrière les exceptions dans L'objectif-C).

S'ils peuvent garantir qu'entre votre appel à unarchiveObjectWithData: et le point dans le code où ils soulèvent l'exception n'est pas de code étranger (ni le tiers ni le code de votre application) il est en théorie possibilité d'utiliser en toute sécurité une exception, à condition que le code d'appel s'occupe correctement du nettoyage.

le problème est que cette hypothèse pourrait ne pas être le cas: il est courant d'utiliser NSKeyedArchiver pour sérialiser des objets personnalisés. Habituellement, la classe personnalisée implémente initWithCoder: pour lire les données des classes (en utilisant les méthodes de l'archiveur comme decodeObjectForKey: ).

si l'archiveur jette une exception dans l'une de ces méthodes, il n'y a aucun moyen de fixer la manipulation des ressources pour l'archiveur. L'exception sera lancée à travers le initWithCoder: de l'objet personnalisé . L'archiveur ne sait pas s'il y a plus de choses à nettoyer que les objets désirés. Donc, dans ce scénario, l'apparition de l'exception signifie que le processus est dans un état dangereux et indésirable comportement peut entraîner.

concernant vos questions:

Pourquoi ne pas [NSKeyedArchiver utilisation appropriée de Cacao erreur la manipulation]?

seuls les ingénieurs D'Apple qui ont construit l'archiver savent. À mon avis, la gestion des exceptions et l'archivage à clé ont été construits à peu près au même moment (vers 2001) et à ce moment-là, il n'était pas encore clair que la gestion des exceptions ne serait jamais un citoyen de première classe dans L'objectif-C.

est-ce que le motif @ try est correct?

avec la limitation des mises en garde décrites ci-dessus, il est correct. si le code D'Apple traite correctement les cas d'exception et votre propre code de sérialisation fait la même chose que le motif @try pourrait être correct.

il est très difficile d'obtenir la pleine exactitude, cependant. Vous devez vous assurer que tout le code exécuté est conscient des exceptions et effectue le nettoyage correctement.

de l'ARC, par exemple, ne fait pas exception nettoyage pour les variables locales et les objets temporaires par défaut (vous devez activer -fobjc-arc-exceptions pour le faire).

aussi, il n'y a pas de documentation sur la sécurité d'exception des accesseurs de @propriétés synthétisées (quand atomic ils pourraient fuir une serrure).

Conclusion:

il y a une myriade de façons subtiles de comment les exceptions peuvent briser des choses. Il est difficile et nécessite une connaissance approfondie de la mise en œuvre de tous les parties impliquées pour construire le code de sécurité d'exception dans L'objectif-C.

tout cela mène à la conclusion. Si vous voulez gérer les erreurs avec élégance pendant le chargement d'archives éventuellement corrompues et continuer l'exécution normale après: N'utilisez pas NSKeyedArchiver .

9
répondu Nikolai Ruhe 2013-12-07 00:49:47
la source

il y avait une nouvelle méthode ajoutée dans iOS 9 à NSKeyedUnarchiver qui retourne maintenant une erreur:

Swift:

public class func unarchiveTopLevelObjectWithData(data: NSData) throws -> AnyObject?

Objectif-C:

+ (nullable id)unarchiveTopLevelObjectWithData:(NSData *)data error:(NSError **)error;

cependant, ce n'est pas compatible avec les versions précédentes de iOS, vous aurez donc besoin de vérifier la disponibilité du framework .

18
répondu Senseful 2017-05-23 15:00:06
la source