Geschützte Methoden in Objective-C

112

Was entspricht geschützten Methoden in Objective-C? Ich möchte Methoden definieren, die nur die abgeleiteten Klassen aufrufen / implementieren dürfen.

LK.
quelle

Antworten:

47

Sie können eine Methode weder als geschützt noch als privat deklarieren . Die Dynamik von Objective-C macht es unmöglich, Zugriffskontrollen für Methoden zu implementieren. (Sie können dies tun, indem Sie den Compiler oder die Laufzeit mit einer schwerwiegenden Geschwindigkeitsstrafe stark ändern, dies wird jedoch aus offensichtlichen Gründen nicht durchgeführt.)

Entnommen aus der Quelle .

Sachin Shanbhag
quelle
Während Sie dies technisch nicht können, können Sie private Variablen emulieren.
Sharen Eayrs
Lee - Wenn Sie einen Funktionszeiger in @protected deklarieren und eine Funktion in der init-Methode zuweisen, würde das funktionieren?
Bikram990
156

Sie können den geschützten und privaten Zugriff auf Methoden folgendermaßen simulieren :

  • Deklarieren Sie Ihre privaten Methoden in einer Klassenerweiterung (dh einer unbenannten Kategorie, die oben in der .m-Datei der Klasse deklariert ist).
  • Deklarieren Sie Ihre geschützten Methoden in einem Subclass-Header - Apple verwendet dieses Muster in Bezug auf UIGestureRecognizer (siehe Dokumentation und Verweis auf UIGestureRecognizerSubclass.h).

Diese Schutzmaßnahmen werden, wie Sachin feststellte, zur Laufzeit nicht durchgesetzt (wie dies beispielsweise in Java der Fall ist).

Brian Westphal
quelle
2
Informationen zur UIGestureRecognizer-ähnlichen Lösung: Das Problem besteht darin, dass Code, der die Unterklasse importiert, auch den Unterklassenheader importiert und daher Zugriff auf die "geschützten" Methoden hat. Gibt es einen Weg, das zu umgehen?
Yonix
5
Hallo yonix, der Import für den Unterklassen-Header würde innerhalb der .m-Datei und nicht innerhalb der .h-Datei erfolgen, sodass beim Importieren der Unterklasse diese geschützten Methoden nicht importiert würden.
Brian Westphal
Cooler Vorschlag Brian, vielen Dank !! Stellen Sie für das ursprüngliche Poster für deklarierte Eigenschaften einfach sicher, dass Sie @dynamic in der Implementierung der Klassenerweiterung (unbenannte Kategorie) der Unterklasse verwenden, damit zur Laufzeit die Implementierung der übergeordneten Klasse verwendet wird
user1046037
1
Wie sehe ich UIGestureRecognizerSubclass.h?
Sharen Eayrs
5
Vielen Dank, dass Sie darauf hingewiesen haben, wie Apple dies intern tut. Ich habe ein vollständiges Beispiel veröffentlicht, wie man Dinge genauso implementiert wie AppleUIGestureRecognizerSubclass.h
Dirty Henry
14

Folgendes habe ich getan, um geschützte Methoden für meine Unterklassen sichtbar zu machen, ohne dass sie die Methoden selbst implementieren müssen. Dies bedeutete, dass ich in meiner Unterklasse keine Compiler-Warnungen über eine unvollständige Implementierung erhielt.

SuperClassProtectedMethods.h (Protokolldatei):

@protocol SuperClassProtectedMethods <NSObject>
- (void) protectMethod:(NSObject *)foo;
@end

@interface SuperClass (ProtectedMethods) < SuperClassProtectedMethods >
@end

SuperClass.m: (Der Compiler zwingt Sie jetzt, geschützte Methoden hinzuzufügen.)

#import "SuperClassProtectedMethods.h"
@implementation SuperClass
- (void) protectedMethod:(NSObject *)foo {}
@end

SubClass.m:

#import "SuperClassProtectedMethods.h"
// Subclass can now call the protected methods, but no external classes importing .h files will be able to see the protected methods.
Michael Kernahan
quelle
2
Die Bedeutung von geschützt ist, dass es nicht extern aufgerufen werden kann. Sie können weiterhin alle in der Klasse definierten Methoden aufrufen, unabhängig davon, ob sie extern sichtbar sind oder nicht.
Eonil
Ja, ich verstehe das. Diese Methode funktioniert für das menschliche Gehirn, nicht für den tatsächlich kompilierten Code. Aber Objective-C erlaubt das nicht (nicht in der Lage zu sein, extern anzurufen). Sie können immer performSelectordarauf.
Michael Kernahan
1
Sie können auch tun [(id)obj hiddenMethod]. Genau genommen wird die geschützte Methode in Objective-C nicht unterstützt.
Eonil
Das Problem dabei ist, dass Ihre sogenannten geschützten Klassen keine Eigenschaften für Anzeigen anzeigen können. Wenn Sie keine Eigenschaften benötigen, ist jedem bekannt, dass Sie einfach geschützte Kategorien hinzufügen können.
Sharen Eayrs
@eonil: "Sie können auch [(id) obj hiddenMethod] ausführen." Ja, Sie können dies tun, aber Sie erhalten eine Warnung vom Compiler, wenn diese Methode in keiner enthaltenen Schnittstelle enthalten ist.
Kaiserludi
9

Ich habe dies gerade entdeckt und es funktioniert für mich. Um Adams Antwort zu verbessern, führen Sie in Ihrer Oberklasse eine Implementierung der geschützten Methode in der .m-Datei durch, deklarieren Sie sie jedoch nicht in der .h-Datei. Erstellen Sie in Ihrer Unterklasse eine neue Kategorie in Ihrer .m-Datei mit der Deklaration der geschützten Methode der Oberklasse, und Sie können die geschützte Methode der Oberklasse in Ihrer Unterklasse verwenden. Dies verhindert letztendlich nicht, dass der Aufrufer der angeblich geschützten Methode zur Laufzeit gezwungen wird.

/////// SuperClass.h
@interface SuperClass

@end

/////// SuperClass.m
@implementation SuperClass
- (void) protectedMethod
{}
@end

/////// SubClass.h
@interface SubClass : SuperClass
@end

/////// SubClass.m
@interface SubClass (Protected)
- (void) protectedMethod ;
@end

@implementation SubClass
- (void) callerOfProtectedMethod
{
  [self protectedMethod] ; // this will not generate warning
} 
@end
Redwud
quelle
2
In diesem Fall warnt der Compiler immer noch vor einer nicht implementierten MethodeprotectedMethod
skywinder
Dies ist eine gute Lösung, aber anstatt eine Kategorie (geschützt) zu erstellen, können Sie eine Erweiterung erstellen.
Dharmesh Siddhpura
@skywinder Vielleicht war es in einer früheren Version so, aber die aktuellen Versionen von Xcode haben mit dieser Lösung kein Problem.
Darren Ehlers
2

Eine andere Möglichkeit, @protected-Variablen zu verwenden.

@interface SuperClass:NSObject{
  @protected
    SEL protectedMehodSelector;
}

- (void) hackIt;
@end

@implementation SuperClass

-(id)init{

self = [super init];
if(self) {
 protectedMethodSelector = @selector(baseHandling);
 }

return self;
}

- (void) baseHandling {

  // execute your code here
}

-(void) hackIt {

  [self performSelector: protectedMethodSelector];
}

@end

@interface SubClass:SuperClass
@end

@implementation SubClass

-(id)init{

self = [super init];
if(self) {
 protectedMethodSelector = @selector(customHandling);
 }

return self;
}

- (void) customHandling {

  // execute your custom code here
}

@end
Marius Bardan
quelle
und Sie können die geschützten IVars in eine Klassenerweiterung in einer Header-Datei mit dem Namen protected auch
einfügen
1

Sie können die Methode als private Methode der übergeordneten Klasse definieren und [super performSelector:@selector(privateMethod)];in der untergeordneten Klasse verwenden.

Chinthakad
quelle
0

Sie können eine Art dies mit einer Kategorie.

@interface SomeClass (Protected)
-(void)doMadProtectedThings;
@end

@implementation SomeClass (Protected)

- (void)doMadProtectedThings{
    NSLog(@"As long as the .h isn't imported into a class of completely different family, these methods will never be seen. You have to import this header into the subclasses of the super instance though.");
}

@end

Die Methoden werden nicht ausgeblendet, wenn Sie die Kategorie in eine andere Klasse importieren, aber Sie tun es einfach nicht. Aufgrund der Dynamik von Objective-C ist es tatsächlich unmöglich, eine Methode unabhängig von einem aufrufenden Instanztyp vollständig auszublenden.

Der beste Weg ist wahrscheinlich die von @Brian Westphal beantwortete Klassenfortsetzungskategorie, aber Sie müssen die Methode in dieser Kategorie für jede untergeordnete Instanz neu definieren.

Adam Waite
quelle
0

Eine Möglichkeit besteht darin, die Klassenerweiterung zum Ausblenden von Methoden zu verwenden.

In .h:

@interface SomeAppDelegate : UIResponder <UIApplicationDelegate>

@property (strong, nonatomic) UIWindow *window;

@end

In .m:

@interface SomeAppDelegate()
- (void)localMethod;
@end

@implementation SomeAppDelegate

- (void)localMethod
{
}

@end
Oh ho
quelle
Ich glaube nicht, dass Sie die @interfaceDeklaration in der .m-Datei brauchen. Sie können einfach eine Funktion deklarieren und verwenden, und sie wird als privat behandelt.
Russ
1
Beachten Sie, dass dies nur für die letzten Aktualisierungen in Ziel C gilt. Zuvor mussten Sie die Methode in einer Schnittstelle deklarieren, da Sie sonst zumindest eine Warnung erhalten würden.
Guillaume Laurent
0

Normalerweise benenne ich geschützte Methoden mit internem Präfix:

-(void) internalMethod;
lbsweek
quelle