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

112

Что эквивалентно защищенным методам в Objective-C? Я хочу определить методы, которые могут вызывать / реализовывать только производные классы.

LK.
источник

Ответы:

47

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

Взято из источника .

Сачин Шанбхаг
источник
Хотя технически вы не можете, вы можете эмулировать частные переменные.
Sharen Eayrs
Ли - если вы объявите указатель на функцию в @protected и назначите функцию в методе инициализации, это сработает?
bikram990
156

Вы можете смоделировать защищенный и частный доступ к методам, выполнив следующие действия:

  • Объявите свои частные методы в расширении класса (т. Е. В безымянной категории, объявленной в верхней части файла .m класса)
  • Объявите свои защищенные методы в заголовке подкласса - Apple использует этот шаблон в отношении UIGestureRecognizer (см. Документацию и ссылку на UIGestureRecognizerSubclass.h)

Эти средства защиты, как заметил Сачин, не применяются во время выполнения (как, например, в Java).

Брайан Вестфаль
источник
2
О решении типа UIGestureRecognizer: проблема в том, что если какой-то код импортирует подкласс, он также импортирует заголовок подкласса и, следовательно, получит доступ к «защищенным» методам. Есть ли способ обойти это?
yonix
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.
eonil
Проблема в том, что ваши так называемые защищенные классы не могут рекламировать свойства. Если свойства не нужны, то всем прекрасно известно, что можно просто добавить защищенные категории.
Шерен Эйрс,
@eonil: «Вы также можете использовать [(id) obj hiddenMethod]». Да, вы можете это сделать, но вы получите предупреждение от компилятора, если этого метода нет ни в одном из включенных интерфейсов.
Kaiserludi
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
Redwud
источник
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 в расширение класса в файл заголовка с именем protected тоже
malhal 08
1

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

Chinthakad
источник
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 файле. Вы можете просто объявить функцию и использовать ее, и она будет рассматриваться как закрытая.
Russ
1
Обратите внимание, что это верно только для последних обновлений в Objective C. До этого вам нужно было объявить метод в интерфейсе, иначе вы, по крайней мере, получите предупреждение.
Guillaume Laurent
0

Я обычно называю защищенный метод внутренним префиксом:

-(void) internalMethod;
lbsweek
источник