2009-05-12 4 views
17

Je pensais avoir une assez bonne sur la gestion de la mémoire pour Objective-C, mais je ne peux pas comprendre la situation suivante:En objectif-C (iphone), comment gérer la mémoire des références '@protocol'?


@protocol MyProtocol 
@end 

@interface MyObject : NSObject { 
    id<MyProtocol> reference; 
} 
@property (nonatomic, retain) id<MyProtocol> reference; 
@end 

@implementation MyObject 
@synthesize reference; 
-(void) dealloc { 
    [reference release]; 
    [super dealloc]; 
} 
... 
@end 

Cela me donne un "avertissement : '-release' introuvable dans le (s) protocole (s) ". Puis-je ignorer cette erreur en toute sécurité? Ou est-ce que je fais quelque chose d'horriblement mal?

Répondre

30

Oui, vous pouvez ignorer cette erreur en toute sécurité. Un objet déclaré comme type id<MyProtocol> ne peut pas hériter de NSObject (vous n'avez pas avoir pour utiliser les bibliothèques Cocoa pour programmer dans Objective-C et il y a d'autres classes racine même dans Cocoa comme NSProxy). Puisque retain (et release, autorelease) sont déclarées dans NSObject, le compilateur ne peut pas savoir que l'instance déclarée comme le type id<MyProtocol> répond à ces messages. Pour contourner cela, Cocoa définit également le protocole NSObject qui reflète l'API NSObject. Si vous déclarez votre protocole comme

@protocol MyProtocol <NSObject> 
@end 

indiquant que MyProtocol étend le protocole NSObject, vous serez fixés.

13

Habituellement, lorsque vous déclarez un objet comme id il compte un objet "any" (ce qui signifie que Objective-C vous permettra d'invoquer n'importe quelle méthode de n'importe quelle classe ou protocole sur le id sans avertissement). Toutefois, lorsque vous déclarez un objet en tant que id<SomeProtocol>, la signification change. Dans ce cas, vous dites plutôt: Je n'appellerai que des méthodes SomeProtocol sur cet objet.

La méthode:

- (void)release; 

est déclaré dans le protocole NSObject mais vous avez dit explicitement: Je ne MyProtocol invoquer les méthodes. Ainsi, le compilateur vous donne un avertissement pour vous dire que vous avez rompu votre propre promesse.

Par conséquent, au lieu de:

id<MyProtocol> reference; 

vous devez déclarer réellement:

id<MyProtocol, NSObject> reference; 

ou:

NSObject<MyProtocol> reference; 

depuis NSObject (la classe) implémente NSObject (le protocole).

ou:

id reference; 

qui est le plus large du lot: permettez-moi de quoi que ce soit sur cet invoque objet et ne jamais se plaindre.

Vous pouvez également (comme Barry Wark a suggéré) ont MyProtocol comprennent le protocole NSObject - même si du point de vue de la conception, vous normalement faire si la mise en œuvre MyProtocol signifie nécessairement utiliser NSObject. Normalement, nous le faisons seulement si NSObject et MyProtocol sont liés héritairement ou sémantiquement.


Un peu plus d'informations sur le protocole NSObject:

Tout ce que vous invoquez conserver/release/autorelease sur doit mettre en œuvre ce protocole. Comme vous pouvez déduire de ceci: fondamentalement tout implémente le protocole NSObject (même si quelques choses ne descendent pas de la classe de base NSObject).

Une autre clarification rapide: NSObject (la classe) et NSObject (le protocole) ne sont pas des réimplémentations de la même API. Ils se répartissent comme suit:

  • NSObject (protocole) met tout en œuvre nécessaire pour gérer/inspecter un objet existant dans un sens générique (conserver/libération, isEqual, classe, respondsToSelector etc).

  • NSObject (class) implémente des méthodes moins génériques: construction/destruction, intégration de thread, intégration de scripts.

Donc dans la plupart des sens, le protocole est le plus important des deux. Rappelez-vous que la classe inclut le protocole, donc si vous descendez de NSObject, vous obtenez les deux.

-2

changement

@property (nonatomic, retain) id<MyProtocol> reference; 

à

@property (nonatomic, assign) id<MyProtocol> reference; 

Pourquoi prendre la peine de conserver l'objet d'implémentation du protocole? Tout ce dont vous avez besoin est un pointeur vers l'objet par lequel nous pouvons appeler des méthodes déclarées dans votre protocole.

+0

Et s'il est désalloué? – user102008

+0

Vous ne pouvez pas supposer qu'il n'a pas besoin de conserver l'objet sans plus de contexte. – pablasso

Questions connexes