Защищенные методы в Objective-C
Что эквивалентно защищенным методам в Objective-C? Я хочу определить методы, которые могут вызывать / реализовывать только производные классы.
8 ответов
Вы не можете объявить метод защищенным или закрытым. Динамическая природа Objective-C делает невозможным реализацию контроля доступа для методов. (Вы могли бы сделать это, сильно изменив компилятор или время выполнения, с серьезным снижением скорости, но по понятным причинам это не сделано.)
Взято из источника.
Вы можете моделировать защищенный и закрытый доступ к методам, выполнив следующие действия:
- Объявите ваши закрытые методы в расширении класса (т.е. безымянная категория, объявленная в верхней части файла класса.m)
- Объявите ваши защищенные методы в заголовке подкласса - Apple использует этот шаблон в отношении UIGestureRecognizer (см. Документацию и ссылку на UIGestureRecognizerSubclass.h).
Эти защиты, как отметил Сачин, не применяются во время выполнения (как, например, в Java).
Вот что я сделал, чтобы сделать защищенные методы видимыми для моих подклассов, не требуя от них реализации самих методов. Это означало, что я не получил предупреждения компилятора в моем подклассе о неполной реализации.
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
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.
Я только что обнаружил это, и оно работает для меня. Чтобы улучшить ответ Адама, в своем суперклассе сделайте реализацию защищенного метода в файле.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
Другой способ, используя @защищенные переменные.
@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
Вы можете определить метод как частный метод родительского класса и можете использовать [super performSelector:@selector(privateMethod)];
в детском классе.
Один из вариантов - использовать расширение класса, чтобы скрыть методы.
В .h
:
@interface SomeAppDelegate : UIResponder <UIApplicationDelegate>
@property (strong, nonatomic) UIWindow *window;
@end
В .m
:
@interface SomeAppDelegate()
- (void)localMethod;
@end
@implementation SomeAppDelegate
- (void)localMethod
{
}
@end
Я обычно называю защищенный метод внутренним префиксом:
-(void) internalMethod;
Вы можете сделать это с категорией.
@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, но вам придется переопределить метод в этой категории для каждого подклассового экземпляра.