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.

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 .


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).


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.

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

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

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.


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.


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

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;
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.