Metody chronione w Objective-C

112

Jaki jest odpowiednik metod chronionych w Objective-C? Chcę zdefiniować metody, które mogą wywoływać / implementować tylko klasy pochodne.

LK.
źródło

Odpowiedzi:

47

Nie możesz zadeklarować metody chronionej ani prywatnej. Dynamiczna natura Objective-C uniemożliwia implementację kontroli dostępu do metod. (Możesz to zrobić, mocno modyfikując kompilator lub środowisko uruchomieniowe, z poważną karą szybkości, ale z oczywistych powodów nie jest to zrobione).

Zaczerpnięte ze źródła .

Sachin Shanbhag
źródło
Chociaż technicznie nie możesz, możesz emulować zmienne prywatne.
Udostępnij Eayrs
Lee - jeśli zadeklarujesz wskaźnik funkcji w @protected i przypiszesz funkcję w metodzie init, czy to zadziała?
bikram990
156

Możesz zasymulować chroniony i prywatny dostęp do metod, wykonując następujące czynności:

  • Zadeklaruj swoje metody prywatne w rozszerzeniu klasy (tj. W nienazwanej kategorii zadeklarowanej w górnej części pliku .m klasy)
  • Zadeklaruj chronione metody w nagłówku podklasy - firma Apple używa tego wzorca w odniesieniu do UIGestureRecognizer (zobacz dokumentację i odniesienie do UIGestureRecognizerSubclass.h)

Te zabezpieczenia nie są, jak zauważył Sachin, wymuszane w czasie wykonywania (jak na przykład w Javie).

Brian Westphal
źródło
2
O rozwiązaniu podobnym do UIGestureRecognizer: Problem polega na tym, że jeśli jakiś kod zaimportuje podklasę, zaimportuje również nagłówek podklasy i dlatego będzie miał dostęp do metod „chronionych”. Czy jest na to sposób?
yonix
5
Cześć yonix, import nagłówka podklasy byłby wykonywany w pliku .m, a nie w pliku .h, więc importowanie podklasy nie spowoduje zaimportowania tych chronionych metod.
Brian Westphal
Fajna sugestia Brian, wielkie dzięki !! Do oryginalnego plakatu, dla zadeklarowanych właściwości, po prostu upewnij się, że używasz @dynamic w implementacji rozszerzenia klasy podklasy (kategoria bez nazwy), aby w czasie wykonywania została użyta implementacja klasy nadrzędnej
user1046037
1
Jak wyświetlić plik UIGestureRecognizerSubclass.h?
Udostępnij Eayrs
5
Dziękuję za wskazanie, jak Apple robi to wewnętrznie. I napisali pełny przykład tego, jak wdrożyć rzeczy w ten sam sposób robi w jabłkoUIGestureRecognizerSubclass.h
Brudny Henry
14

Oto, co zrobiłem, aby chronione metody były widoczne dla moich podklas, bez konieczności ich implementacji. Oznaczało to, że nie otrzymałem ostrzeżeń kompilatora w mojej podklasie o niekompletnej implementacji.

SuperClassProtectedMethods.h (plik protokołu):

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

@interface SuperClass (ProtectedMethods) < SuperClassProtectedMethods >
@end

SuperClass.m: (kompilator wymusi teraz dodanie chronionych metod)

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

Podklasa 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
źródło
2
Znaczenie chronionych oznacza, że nie można ich nazwać zewnętrznie. Nadal można wywoływać metody zdefiniowane w klasie, niezależnie od tego, czy są one widoczne zewnętrznie, czy nie.
eonil
Tak, rozumiem to. Ta metoda działa w przypadku ludzkiego mózgu, a nie rzeczywistego skompilowanego kodu. Ale Objective-C nie pozwala na to (brak możliwości wywołania zewnętrznego). Zawsze możesz performSelectorna nim.
Michael Kernahan
1
Ty też możesz to zrobić [(id)obj hiddenMethod]. Dokładnie mówiąc, metoda chroniona nie jest obsługiwana w Objective-C.
eonil
Problem polega na tym, że tak zwane klasy chronione nie mogą wyświetlać właściwości reklam. Jeśli nie potrzebujesz właściwości, każdy doskonale wie, że możesz po prostu dodać chronione kategorie.
Udostępnij Eayrs
@eonil: "Możesz także wykonać [(id) obj hiddenMethod]." Tak, możesz to zrobić, ale otrzymasz ostrzeżenie od kompilatora, jeśli tej metody nie ma w żadnym dołączonym interfejsie.
Kaiserludi
9

Właśnie to odkryłem i działa dla mnie. Aby ulepszyć odpowiedź Adama, w swojej superklasie zrób implementację chronionej metody w pliku .m, ale nie deklaruj jej w pliku .h. W swojej podklasie utwórz nową kategorię w swoim pliku .m z deklaracją chronionej metody nadklasy i możesz użyć chronionej metody nadklasy w swojej podklasie. Nie zapobiegnie to ostatecznie wywołującemu rzekomo chronionej metody, jeśli zostanie wymuszone w czasie wykonywania.

/////// 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
źródło
2
W tym przypadku kompilator nadal wyrzuca ostrzeżenie o niezaimplementowanej metodzieprotectedMethod
skywinder
Jest to dobre obejście, ale zamiast tworzyć kategorię (chronione), możesz dodać rozszerzenie.
Dharmesh Siddhpura
@skywinder Być może we wcześniejszej wersji, ale obecne wersje Xcode nie mają problemu z tym rozwiązaniem.
Darren Ehlers
2

Inny sposób wykorzystania @chronionych zmiennych.

@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
źródło
i możesz umieścić chronione IVars w rozszerzeniu klasy w pliku nagłówkowym o nazwie protected także
malhal
1

Możesz zdefiniować metodę jako prywatną metodę klasy nadrzędnej i używać jej [super performSelector:@selector(privateMethod)];w klasie potomnej.

chinthakad
źródło
0

Można rodzaj zrobić z kategorii.

@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

Metody nie są ukryte, jeśli importujesz kategorię do innej klasy, ale po prostu tego nie robisz. Ze względu na dynamiczny charakter Objective-C niemożliwe jest całkowite ukrycie metody, niezależnie od typu wywołującej instancji.

Najlepszym sposobem jest prawdopodobnie kategoria kontynuacji klasy, na którą odpowiedział @Brian Westphal, ale będziesz musiał ponownie zdefiniować metodę w tej kategorii dla każdej instancji z podklasą.

Adam Waite
źródło
0

Jedną z opcji jest użycie rozszerzenia klasy do ukrycia metod.

W .h:

@interface SomeAppDelegate : UIResponder <UIApplicationDelegate>

@property (strong, nonatomic) UIWindow *window;

@end

W .m:

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

@implementation SomeAppDelegate

- (void)localMethod
{
}

@end
ohho
źródło
Myślę, że nie potrzebujesz nawet @interfacedeklaracji w pliku .m. Możesz po prostu zadeklarować funkcję i użyć jej, a będzie ona traktowana jako prywatna.
Russ
1
Zwróć uwagę, że jest to prawdą tylko w przypadku ostatnich aktualizacji w celu C. Wcześniej trzeba było zadeklarować metodę w interfejsie, w przeciwnym razie przynajmniej pojawi się ostrzeżenie.
Guillaume Laurent
0

Zwykle nazywam metodę chronioną wewnętrznym prefiksem:

-(void) internalMethod;
lbsweek
źródło