17 Stimmen

Wie verwalte ich in Objective-C (iphone) den Speicher von "@protocol"-Referenzen?

Ich dachte, ich hatte einen ziemlich guten Griff auf Speicherverwaltung für Objective-C, aber ich kann nicht herausfinden, die folgende Situation:


@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

Das gibt mir ein " Warnung: '-release' nicht in Protokoll(en) gefunden ". Kann ich diesen Fehler getrost ignorieren? Oder mache ich etwas schrecklich falsch?

29voto

Barry Wark Punkte 106328

Ja, Sie können diesen Fehler getrost ignorieren. Ein als Typ deklariertes Objekt id<MyProtocol> darf nicht erben von NSObject (Sie müssen nicht haben die Cocoa-Bibliotheken zu verwenden, um in Objective-C zu programmieren, und es gibt auch in Cocoa andere Root-Klassen wie NSProxy ). Da retain (und release , autorelease ) werden deklariert in NSObject kann der Compiler nicht wissen, dass die Instanz, die als Typ id<MyProtocol> antwortet auf diese Nachrichten. Um dies zu umgehen, definiert Cocoa auch die NSObject Protokoll die die NSObject API. Wenn Sie Ihr Protokoll als

@protocol MyProtocol <NSObject>
@end

aus dem hervorgeht, dass MyProtocol erweitert die NSObject Protokoll dann sind Sie bereit.

13voto

Matt Gallagher Punkte 14710

Normalerweise, wenn Sie ein Objekt als id Es gilt als "any"-Objekt (was bedeutet, dass Objective-C den Aufruf jeder Methode aus jeder Klasse oder jedem Protokoll auf dem id ohne Vorwarnung).

Wenn Sie jedoch ein Objekt als id<SomeProtocol> , ändert sich die Bedeutung. In diesem Fall sagen Sie stattdessen: Ich werde mich nur auf SomeProtocol Methoden auf dieses Objekt.

Die Methode:

- (void)release;

wird in der Datei NSObject Protokolls, aber Sie haben ausdrücklich darauf hingewiesen: Ich werde mich nur auf MyProtocol Methoden. Der Compiler gibt also eine Warnung aus, um Ihnen mitzuteilen, dass Sie Ihr eigenes Versprechen gebrochen haben.

Daher wird anstelle von:

id<MyProtocol> reference;

sollten Sie eigentlich erklären:

id<MyProtocol, NSObject> reference;

oder:

NSObject<MyProtocol> reference;

seit NSObject (die Klasse) implementiert NSObject (das Protokoll).

oder:

id reference;

die am weitesten gefasst ist: Ich kann mich auf dieses Objekt berufen und mich nie beschweren.

Sie können auch (wie von Barry Wark vorgeschlagen) MyProtocol umfassen die NSObject Protokolls - obwohl Sie dies aus der Sicht des Designs normalerweise nur tun, wenn Sie MyProtocol bedeutet zwangsläufig die Verwendung NSObject . Normalerweise tun wir dies nur, wenn NSObject y MyProtocol vererblich oder semantisch miteinander verbunden sind.


Ein paar Informationen über die NSObject Protokoll:

Alles, worauf Sie retain/release/autorelease anwenden, muss dieses Protokoll implementieren. Wie Sie daraus ableiten können, implementiert im Grunde alles das NSObject Protokoll (auch wenn einige Dinge nicht von der NSObject Basisklasse).

Noch eine kurze Klarstellung: NSObject (die Klasse) und NSObject (das Protokoll) sind keine Neuimplementierungen desselben API. Sie sind wie folgt aufgeteilt:

  • NSObject (Protokoll) implementiert alles, was erforderlich ist, um ein vorhandenes Objekt in einem generischen Sinne zu behandeln/zu untersuchen (retain/release, isEqual, class, respondsToSelector: usw.).

  • NSObject (Klasse) implementiert weniger generische Methoden: Aufbau/Zerstörung, Thread-Integration, Skripting-Integration.

In den meisten Fällen ist also das Protokoll das wichtigere von beiden. Denken Sie daran, dass die Klasse das Protokoll enthält. Wenn Sie also von NSObject abstammen, erhalten Sie beides.

-2voto

helios Punkte 1

Ändern Sie

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

zu

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

Warum sollte man das Objekt, das das Protokoll implementiert, beibehalten? Alles, was Sie brauchen, ist ein Zeiger auf das Objekt, mit dem wir die in Ihrem Protokoll deklarierten Methoden aufrufen können.

0 Stimmen

Sie können nicht davon ausgehen, dass er das Objekt nicht behalten muss, ohne mehr Kontext zu haben.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X