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.

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 .


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


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.

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

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

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.


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


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

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;
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.