Захищені методи в Objective-C


112

Що таке еквівалент захищеним методам у Objective-C? Я хочу визначити методи, які можуть покликати / реалізувати лише похідні класи.

Відповіді:


47

Ви не можете оголосити метод захищеним або приватним. Динамічний характер Objective-C унеможливлює реалізацію засобів контролю доступу до методів. (Ви можете це зробити, сильно змінивши компілятор або час виконання, із суворим покаранням швидкості, але з очевидних причин це не робиться.)

Взято з Джерела .


Хоча технічно ви цього не можете, ви можете імітувати приватні змінні.
Sharen Eayrs

Лі - якщо ви оголосите покажчик функції в @protected і призначите функцію методом init, чи буде це працювати?
bikram990

156

Ви можете імітувати захищений та приватний доступ до методів, виконавши такі дії:

  • Заявіть про ваші приватні методи в розширенні класу (тобто категорія, яка не називається, оголошена біля верхньої частини файлу класу '.m)
  • Заявіть про захищені способи у заголовку підкласу - Apple використовує цей зразок щодо UIGestureRecognizer (див. Документацію та посилання на UIGestureRecognizerSubclass.h)

Як захищав Сачін, ці засоби захисту не застосовуються під час виконання (як, наприклад, у Java).


2
Про подібне рішення UIGestureRecognizer: Проблема полягає в тому, що якщо якийсь код імпортує підклас, він також імпортує заголовок підкласу, і тому він матиме доступ до "захищених" методів. Чи є шлях до цього?
йонікс

5
Привіт yonix, імпорт заголовка підкласу здійснюватиметься всередині файлу .m, а не у файлі .h, тому імпорт підкласу не імпортує ці захищені методи.
Брайан Вестфал

Класна пропозиція Брайан, спасибі тонну !! Для оригінального плаката для оголошених властивостей просто переконайтеся, що ви використовуєте @dynamic в реалізації розширення класу підкласу (без назви), щоб під час виконання використовувалася реалізація батьківського класу
user1046037

1
Як я бачу UIGestureRecognizerSubclass.h?
Sharen Eayrs

5
Дякуємо, що вказали на те, як Apple робить це всередині країни. Я розмістив повний приклад того, як реалізовувати речі так само, як робить AppleUIGestureRecognizerSubclass.h
Брудний Генрі

14

Ось що я зробив, щоб отримати захищені методи, видимі для моїх підкласів, не вимагаючи від них самих методів реалізації. Це означало, що я не отримував попереджень компілятора у своєму підкласі про неповну реалізацію.

SuperClassProtectedMethods.h (файл протоколу):

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

@interface SuperClass (ProtectedMethods) < SuperClassProtectedMethods >
@end

SuperClass.m: (компілятор тепер змусить вас додати захищені методи)

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

Підклас.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
Сенс захищеного полягає в тому, що він не може називатися зовні. Ви все ще можете викликати будь-які методи, визначені в класі, незалежно від того, зовні вони вони видимі чи ні.
eonil

Так, я це розумію. Цей метод працює для людського мозку, а не фактично складений код. Але Objective-C цього не дозволяє (не може здійснювати дзвінки зовнішньо). Ви завжди можете performSelectorна ньому.
Майкл Кернахан

1
Ви також можете зробити [(id)obj hiddenMethod]. Точно кажучи, захищений метод не підтримується в Objective-C.
еоніл

Проблема з цим полягає в тому, що ваші так звані захищені класи не можуть розміщувати властивості реклами. Якщо вам не потрібні властивості, то хтось добре знає, що ви можете просто додати захищені категорії.
Sharen Eayrs

@eonil: "Ви також можете зробити [(id) obj hiddenMethod]." Так, ви можете це зробити, але ви отримаєте попередження від компілятора, якщо цей метод не міститься в будь-якому включеному інтерфейсі.
Кайзерлуді

9

Щойно я виявив це, і це працює на мене. Щоб покращити відповідь Адама, у вашому суперкласі здійсніть реалізацію захищеного методу у файлі .m, але не оголошуйте його у .h-файлі. У своєму підкласі введіть нову категорію у свій .m файл із оголошенням захищеного методу надкласу, і ви можете використовувати захищений метод надкласу у своєму підкласі. Це в остаточному підсумку не завадить абоненту нібито захищеного методу, якщо він буде вимушений під час виконання.

/////// 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
У цьому випадку компілятор все-таки кидає попередження про protectedMethod
безреалізований

Це непогана робота, але замість створення категорії (Захищена), ви можете зробити розширення.
Дхармеш Сиддпура

@skywinder Можливо, це було в більш ранній версії, але поточні версії Xcode не мають проблем з цим рішенням.
Даррен Елерс

2

Інший спосіб використання змінних @protected.

@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

і ви можете помістити захищені IVars у розширення класу у файл заголовка, який також названий захищеним
malhal

1

Ви можете визначити метод як приватний метод батьківського класу і використовувати його [super performSelector:@selector(privateMethod)];в дочірньому класі.


0

Ви можете сортувати це за допомогою категорії.

@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

Методи не є прихованими, якщо ви імпортуєте категорію в інший клас, але ви просто цього не робите. Через динамічний характер Objective-C неможливо повністю приховати метод незалежно від типу виклику екземпляра.

Найкращий шлях - це, мабуть, категорія продовження класу, на яку відповів @Brian Westphal, але вам доведеться переосмислити метод у цій категорії для кожного підкласового примірника.


0

Один з варіантів - використовувати розширення класу, щоб приховати методи.

В .h:

@interface SomeAppDelegate : UIResponder <UIApplicationDelegate>

@property (strong, nonatomic) UIWindow *window;

@end

В .m:

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

@implementation SomeAppDelegate

- (void)localMethod
{
}

@end

Я не думаю, що вам навіть потрібна @interfaceдекларація у файлі .m. Ви можете просто оголосити функцію та використовувати її, і вона буде вважатись приватною.
Русс

1
Зауважте, що це стосується лише останніх оновлень у Цілі C. До цього вам довелося оголосити метод в інтерфейсі, інакше ви хоч би отримали попередження.
Гійом Лоран

0

Зазвичай я називаю захищений метод із внутрішнім префіксом:

-(void) internalMethod;
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.