Objective-C中受保护的方法


112

什么与Objective-C中的受保护方法等效?我想定义仅派生类可以调用/实现的方法。

Answers:


47

您不能将方法声明为保护方法私有方法。Objective-C的动态性质使其无法实现方法的访问控制。(您可以通过严重修改编译器或运行时来实现此目的,但速度会受到严重影响,但是出于明显的原因,这样做并未完成。)

取自Source


从技术上讲,您不能模仿私有变量。
Sharen Eayrs

Lee-如果您在@protected中声明一个函数指针并在init方法中分配一个函数,它将起作用吗?
bikram990 2014年

156

您可以通过执行以下操作来模拟对方法的受保护和私有访问:

  • 在类扩展中声明您的私有方法(即,在类的.m文件顶部附近声明的未命名类别)
  • 在Subclass标头中声明您的受保护方法-Apple针对UIGestureRecognizer使用此模式(请参阅文档和对UIGestureRecognizerSubclass.h的引用)

正如Sachin指出的那样,这些保护不是在运行时强制执行的(例如,在Java中)。


2
关于类似于UIGestureRecognizer的解决方案:问题是,如果某些代码导入了子类,那么它还将导入Subclass头,因此将可以访问“受保护”的方法。有办法解决吗?
yonix 2012年

5
嗨,yonix,子类标头的导入将在.m文件中完成,而不是在.h文件中进行,因此导入子类不会导入这些受保护的方法。
布莱恩·韦斯特法

很酷的建议Brian,非常感谢!对于原始发布者,对于声明的属性,只需确保在子类的类扩展(未命名类别)的实现中使用@dynamic,以便在运行时使用父类的实现
user1046037,2012年

1
我如何看到UIGestureRecognizerSubclass.h?
Sharen Eayrs

5
感谢您指出Apple内部的运作方式。我张贴了一个完整的示例,说明了如何以Apple的相同方式实施操作UIGestureRecognizerSubclass.h
Dirty Henry

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

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.

2
保护的含义是它不能从外部调用。您仍然可以调用类中定义的任何方法,无论它们是否在外部可见。
2012年

是的,我明白这一点。此方法适用于人脑,不适用于实际的编译代码。但是Objective-C不允许这样做(不能从外部调用)。您可以随时performSelector使用它。
Michael Kernahan 2012年

1
您也可以做[(id)obj hiddenMethod]。准确地说,Objective-C不支持受保护的方法。
2012年

问题是您所谓的受保护的类不能广告属性。如果您不需要属性,那么任何人都知道您可以简单地添加受保护的类别。
Sharen Eayrs,2012年

@eonil:“您也可以执行[(id)obj hiddenMethod]。” 是的,您可以执行此操作,但是如果该方法未包含在任何包含的接口中,则会从编译器收到警告。
Kaiserludi

9

我只是发现了这一点,并且对我有用。要改进亚当的答案,请在您的超类中在.m文件中实现protected方法的实现,但不要在.h文件中声明它。在子类中,使用超类的protected方法的声明在.m文件中创建一个新类别,然后可以在子类中使用超类的protected方法。如果在运行时强制执行,这最终不会阻止所谓的受保护方法的调用者。

/////// 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 2014年

这是一个很好的解决方法,但是您可以进行扩展而不是创建类别(受保护)。
Dharmesh Siddhpura

@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,

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
请注意,这仅适用于Objective C中的最新更新。在此之前,您必须在接口中声明该方法,否则至少会收到警告。
纪尧姆·洛朗

0

我通常用内部前缀命名受保护的方法:

-(void) internalMethod;
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.