2009-01-21 3 views

Répondre

51

Avec une variable tapée id, vous pouvez lui envoyer n'importe quel message connu et le compilateur ne se plaindra pas. Avec une variable typée NSObject *, vous pouvez seulement lui envoyer des messages déclarés par NSObject (pas des méthodes de n'importe quelle sous-classe) sinon il va générer un avertissement. En général, id est ce que vous voulez. Explication complémentaire: Tous les objets sont essentiellement de type id. Le point de déclarer un type statique est de dire au compilateur, "Supposons que cet objet est membre de cette classe." Donc, si vous lui envoyez un message que la classe ne déclare pas, le compilateur peut vous dire: "Attendez, cet objet n'est pas censé recevoir ce message!" En outre, si deux classes ont des méthodes avec le même nom mais des signatures différentes (c'est-à-dire, des arguments ou des types de retour), il peut deviner quelle méthode vous voulez dire par la classe que vous avez déclarée pour la variable. S'il est déclaré id, le compilateur lèvera simplement les mains et vous dira: "OK, je n'ai pas assez d'informations ici, je choisis une signature de méthode au hasard." (Ce ne sera généralement pas aidé en déclarant NSObject*, bien. En général, le conflit est entre deux classes plus spécifiques.)

+2

Grande explication, bien que j'hésite à dire que "En général, id est ce que vous voulez". Bien que "id" soit assez flexible en raison du typage dynamique, il ne fournit pratiquement aucun avertissement, donc si vous appelez une méthode non supportée, ce qui pourrait être détecté au moment de la compilation devient un problème d'exécution. Typage statique (avec MyClassName * etc.) lorsqu'il est utilisé judicieusement peut rendre la vie beaucoup plus simple, en particulier lors du débogage dans Xcode (il peut montrer un résumé plus intelligent de l'objet) ou attraper des appels de méthode avec des sélecteurs mal orthographiés ou incomplètes. –

+0

La distinction que je voulais dessiner est spécifiquement entre id et NSObject *, pas de typage statique en général. Il est beaucoup plus commun que vous vouliez utiliser id que statiquement type comme NSObject. – Chuck

+0

@simpleBob: D'où "tout message connu". – Chuck

17

id signifie « un objet », NSObject * signifie « une instance de NSObject ou un de ses sous-classes ». Il y a des objets dans Objective-C qui ne sont pas NSObject s (ceux que vous rencontrerez dans Cocoa pour l'instant sont NSProxy, Protocol et Class). Si du code attend un objet d'une classe particulière, déclarant que cela aide le compilateur à vérifier que vous l'utilisez correctement. Si vous pouvez vraiment prendre "n'importe quel objet" - par exemple vous déclarez un délégué et testera tous les envois de méthode avec respondsToSelector: appels - vous pouvez utiliser un id.

Une autre façon de déclarer une variable d'objet est comme « id <NSObject> », ce qui signifie « tout objet qui implémente le protocole NSObject.

+0

NSProxy et le protocole sont des classes. "Class" n'est pas une classe, mais simplement un type qui peut faire référence à des pointeurs vers des objets de classe. Ne pas les regrouper – user102008

+0

@ user102008: vous pouvez envoyer des messages à une classe, ce qui en fait un objet dans le monde d'objc. –

+0

oui, les objets de classe sont des objets, mais ils ne sont pas d'une classe appelée "Class" – user102008

10

De ma compréhension limitée de Objective-C, tous les objets sont dérivés de NSObject (à la différence Java où tous les objets dérivent de l'objet.) Vous pouvez théoriquement avoir d'autres objets racine.Id pourrait s'appliquer à n'importe lequel de ces objets dérivés non-NSObject

0

Je voudrais ajouter une autre différence lorsque vous ajoutez un protocole à id, ça ne veut plus dire qu'il sera de type NSObject *, ça veut tout simplement dire que ce sera tout s qui confirme à ce protocole.

Ainsi, par exemple, ce code ne sera pas jeter toute erreur, catégorie NSDelayedPerforming a l » depuis NSObject cette méthode:

id testId; 
[testId performSelector:@selector(isKindOfClass:) withObject:[NSObject class] afterDelay:.5]; 

Cependant, ce code affiche l'erreur No known instance method for selector "performSelector:withObject:afterDelay:":

id<NSMutableCopying> testId; 
[testId performSelector:@selector(isKindOfClass:) withObject:[NSObject class] afterDelay:.5]; 
Questions connexes