En Objective-C pourquoi devrais-je vérifier si l'auto = [super init] est non nul?

StackOverflow https://stackoverflow.com/questions/1287950

  •  18-09-2019
  •  | 
  •  

Question

J'ai une question générale sur l'écriture des méthodes d'initialisation en Objective-C.

Je vois partout (code d'Apple, les livres, le code open source, etc.) qu'une méthode d'initialisation doit vérifier si l'auto = [super init] est non nul avant de poursuivre l'initialisation.

Le modèle par défaut Apple pour une méthode d'initialisation est:

- (id) init
{
    self = [super init];

    if (self != nil)
    {
        // your code here
    }

    return self;
}

Pourquoi?

Je veux dire quand est l'init va jamais revenir nulle? Si j'ai appelé init NSObject et ai nul retour, alors quelque chose doit être vraiment vissé, non? Et dans ce cas, vous pourriez aussi bien même pas écrire un programme ...

Est-il vraiment commun qu'une méthode d'initialisation de classe peut retourner nul? Si oui, dans quel cas, et pourquoi?

Était-ce utile?

La solution

Par exemple:

[[NSData alloc] initWithContentsOfFile:@"this/path/doesn't/exist/"];
[[NSImage alloc] initWithContentsOfFile:@"unsupportedFormat.sjt"];
[NSImage imageNamed:@"AnImageThatIsntInTheImageCache"];

... et ainsi de suite. (Note: NSData peut lancer une exception si le fichier n'existe pas). Il y a quelques domaines où le retour nul est le comportement attendu lorsqu'un problème se produit, et à cause de cela, il est pratique courante pour vérifier à peu près nul tout le temps, par souci de cohérence.

Autres conseils

Cet idiome particulier est standard parce que cela fonctionne dans tous les cas.

Bien que rare, il y aura des cas où ...

[super init];

... renvoie une autre instance, ce qui nécessite l'affectation à l'auto.

Et il y aura des cas où il retournera nul, ce qui nécessite le contrôle nul afin que votre code ne cherche pas à initialiser une instance fente variable qui n'existe plus.

La ligne de fond est qu'il est le modèle correct documenté à utiliser et, si vous ne l'utilisez pas, vous le faites mal.

Je pense que, dans la plupart des classes, si la valeur de retour de [super init] est nul et vous le vérifier, tel que recommandé par les pratiques standard, puis revenir prématurément si nul, essentiellement votre application est toujours ne va pas fonctionner correctement. Si vous pensez à ce sujet, même si que si (auto! = Nil) chèque est là, pour le bon fonctionnement de votre classe, 99,99% du temps que vous avez réellement faire besoin de soi pour être non nulle. Maintenant, supposons que, pour une raison quelconque, [super init] ne nul retour, essentiellement votre chèque contre zéro est essentiellement passer la balle à l'appelant de votre classe, où il échouerait probablement de toute façon, puisqu'il supposera naturellement que l'appel a réussi.

En fait, ce que je veux dire est que 99,99% du temps, si le (auto! = Nul) ne vous achète pas quoi que ce soit en termes de robustesse plus, puisque vous êtes juste passer la balle à votre invocateur . Pour vraiment être en mesure de gérer ce besoin avec vigueur, vous en fait de mettre des contrôles dans votre hiérarchie complète d'appel. Et même alors, la seule chose qu'il achèteriez-vous que votre application ne permettrait pas un peu plus proprement / avec vigueur. Mais il serait toujours pas.

Si le résultat d'un [super init] classe bibliothèque a décidé de revenir arbitrairement nul comme, vous êtes à peu près f *** ed de toute façon, et c'est plus d'une indication que l'auteur de la classe de la bibliothèque a fait une erreur de mise en œuvre.

Je pense que cela est plus d'une suggestion de codage de l'héritage, lorsque les applications ont couru dans beaucoup plus de mémoire limitée.

Mais pour le code de niveau C, je reste généralement vérifier la valeur de retour de malloc () contre un pointeur NULL. Considérant que, pour Objective-C, jusqu'à ce que je trouve la preuve du contraire, je pense que je vais passer généralement si les contrôles (auto! = Néant). Pourquoi cette différence?

Parce que, au niveau C et malloc, dans certains cas, vous pouvez effectivement partiellement récupérer. Alors que je pense à Objective-C, dans 99,99% des cas, si [super init] ne retour nul, vous êtes essentiellement f *** ed, même si vous essayez de le manipuler. Vous pourriez tout aussi bien laisser le plantage de l'application et de faire face aux conséquences.

C'est en quelque sorte un résumé des commentaires ci-dessus.

Disons que le rendement de la superclasse nil. Qu'est-ce qui va arriver?

Si vous ne suivez pas les conventions

Votre code est va plantage au milieu de votre méthode de init. (À moins que init ne fait rien d'importance)

Si vous suivez les conventions, ne sachant pas que la superclasse pourrait retourner nul (la plupart des gens finissent par ici)

Votre code est probalby va accident à un moment plus tard, parce que votre exemple est nil, où vous attendiez quelque chose de différent. Ou votre programme va se comporter de façon inattendue sans se briser. Oh cher! Voulez-vous cela? Je ne sais pas ...

Si vous suivez les conventions, ce qui permet volontiers votre sous-classe pour revenir nulle

La documentation de votre code doit indiquer clairement (!): « Retours ... ou nul », et le reste de votre code doit être préparé pour traiter ce sujet. Maintenant, il est logique.

En règle générale, si votre classe dérive directement de NSObject, vous ne aurez pas besoin. Cependant, il est une bonne habitude à prendre, comme si votre classe dérive d'autres classes, leurs initializers peuvent retourner nil, et si oui, votre initialiseur peut alors capturer cela et se comporter correctement.

Et oui, pour l'enregistrement, je suis la meilleure pratique et d'écrire sur toutes mes classes, même celles qui découlent directement de NSObject.

Vous avez raison, vous pouvez souvent juste écrire [super init], mais cela ne fonctionnerait pas pour une sous-classe de quoi que ce soit juste. Les gens préfèrent simplement mémoriser une ligne standard de code et l'utiliser tout le temps, même quand il est seulement parfois nécessaire, et donc nous obtenons la if (self = [super init]) standard, qui prend à la fois la possibilité de néant son retour et la possibilité d'un objet autre que self être renvoyé en compte.

Une erreur courante consiste à écrire

self = [[super alloc] init];

qui renvoie une instance de la superclasse, qui n'est pas ce que vous voulez dans une sous-classe constructeur / init. Vous revenez d'un objet qui ne répond pas aux méthodes de sous-classe, ce qui peut être source de confusion, et de générer des erreurs confuses de ne pas reponding à des méthodes ou des identificateurs non trouvé, etc.

self = [super init]; 

est nécessaire si la super classe a des membres (variables ou autres objets) pour initialiser first avant la mise en place des membres des sous-classes. Sinon, le moteur d'exécution objc les initialise tous les 0 ou nil . ( contrairement à la norme ANSI C, qui attribue souvent des morceaux de mémoire sans les effacer du tout )

Et oui, l'initialisation de la classe de base peut échouer en raison d'erreurs hors de mémoire, des composants manquants, les défaillances d'acquisition de ressources, etc. donc un chèque nul est sage, et prend moins de quelques millisecondes.

Il est de vérifier que le intialazation a travaillé, l'instruction if renvoie true si la méthode init n'a pas retourné nul, de sorte que son moyen de vérifier la création de l'objet a fonctionné correctement. Peu de raisons que je peux penser que init pourrait peut-être échouer sa méthode init que surchargée super classe ne connaît pas ou quelque chose du genre, je ne reviendrai pas pense qu'il est que si commune. Mais si cela arrive, son meilleur ne se passe rien qu'un accident je supose donc est toujours vérifiée ...

Dans OS X, il est pas aussi probable -[NSObject init] à l'échec pour des raisons de mémoire. On ne peut pas dire pour iOS.

, il est aussi une bonne pratique pour l'écriture lorsque le sous-classement une classe qui pourrait revenir nil pour une raison quelconque.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top