向子类公开私有Objective-C方法或属性

向子类公开私有Objective-C方法或属性,objective-c,inheritance,subclass,visibility,declared-property,Objective C,Inheritance,Subclass,Visibility,Declared Property,根据一些官方谈话,Objective-C中的类应该只在其头中公开公共方法和属性: @interface MyClass : NSObject @property (nonatomic, strong) MyPublicObject *publicObject; - (void)publicMethod; @end 私有方法/属性应保存在.m文件的类扩展名中: @interface MyClass() @property (nonatomic, strong) MyPrivateObje

根据一些官方谈话,Objective-C中的类应该只在其头中公开公共方法和属性:

@interface MyClass : NSObject

@property (nonatomic, strong) MyPublicObject *publicObject;

- (void)publicMethod;

@end
私有方法/属性应保存在.m文件的类扩展名中:

@interface MyClass()

@property (nonatomic, strong) MyPrivateObject *privateObject;

- (void) privateMethod;

@end

我认为对于私有但可从子类访问的事物,不存在
受保护的
类型。我想知道,除了公开声明私有属性/方法之外,还有什么方法可以实现这一点吗?

您唯一的选择是在头文件中将其声明为公共。如果您想至少保持一些方法分离,您可以创建一个类别,并将所有受保护的方法和属性都放在那里,但最终所有内容都将是公共的

#import "MyClass.h"

@interface MyClass (Protected)

- (void) protectedMethods;

@end

那是因为私人和公共之间甚至没有真正的区别。虽然编译器可能会警告您某个接口缺少某个方法或实例变量,但您的程序仍然可以工作。

解决此问题的一种方法是在子类的类扩展中重新声明属性,然后添加一个
@dynamic
语句,这样编译器就不会创建该属性的重写实现。比如:

@interface SuperClass ()

@property (nonatomic, strong) id someProperty;

@end

....


@interface SubClass ()

@property (nonatomic, strong) id someProperty;

@end

@implementation SubClass

@dynamic someProperty;

@end
这显然不理想,因为它复制了一个私人可见的声明。但在某些情况下,它非常方便和有用,所以我想说,在个案的基础上评估这种复制与在公共界面中暴露财产所涉及的危险


苹果在UIGestureRecognitizer中使用的另一种方法是在单独的类别头文件中声明属性,该文件显式命名为“private”或“protected”,例如“SomeClass+protected.h”。这样,其他程序员就会知道他们不应该导入该文件。但是,如果您不控制从中继承的代码,则这不是一个选项。

虽然其他答案是正确的,但我想添加

私有、受保护和公共变量可用,例如变量

@interface MyClass : NSObject {
@private
  int varA;

@protected
  int varB;

@public
  int varC;
}

@end

这可以通过使用包含在基类和子类的实现文件中的类扩展名(而不是类别)来实现

类扩展的定义类似于类别,但没有类别名称:

@interface MyClass ()
在类扩展中,您可以声明属性,这将能够合成支持IVAR(XCode>4.4 IVAR的自动合成在这里也起作用)

在扩展类中,您可以重写/优化属性(将readonly更改为readwrite等),并添加对实现文件“可见”的属性和方法(但请注意,属性和方法不是真正私有的,仍然可以由选择器调用)

其他人建议为此使用单独的头文件MyClass_protected.h,但也可以在主头文件中使用
\ifdef
这样做:

例如:

基类.h

基类.m

儿童班

@interface SomeChildClass : SomeSuperClass
儿童班

@interface SomeSuperClass (exposePrivateMethod)
-(void)somePrivateMethod:(NSString*)someArgument;
@end

@implementation SomeChildClass

-(void)doSomething {
    [super somePrivateMethod:@"argument"];
}

@end
当您调用
#import
时,它基本上会将.h文件复制粘贴到您要导入它的位置。 如果您有一个
#ifdef
,则只有在设置了带有该名称的
#define
时,它才会将代码包含在其中

在.h文件中,您没有设置define,因此任何导入此.h的类都不会看到受保护的类扩展名。
在基类和子类.m文件中,在使用
\import
之前使用
\define
,这样编译器将包含受保护的类扩展名。

只需使用类扩展名创建一个.h文件。将其导入.m文件。顺便说一句,这是一种在不破坏封装的情况下测试私有成员的好方法(我不是说您应该测试私有方法:)

/////////////////

#import "MyClassProtectedMembers.h"

@implementation MyClass
// implement privateMethod here and any setters or getters with computed values
@end

这里是这个想法的要点:

我看到了使属性可见的好答案,但我没有看到在这些答案中非常清楚地暴露出所述的方法。下面是我如何使用一个类别成功地向子类公开私有方法的:

SomeSuperClass.m:

@implementation SomeSuperClass

-(void)somePrivateMethod:(NSString*)someArgument {
    ...
}
某个儿童班

@interface SomeChildClass : SomeSuperClass
一些儿童班

@interface SomeSuperClass (exposePrivateMethod)
-(void)somePrivateMethod:(NSString*)someArgument;
@end

@implementation SomeChildClass

-(void)doSomething {
    [super somePrivateMethod:@"argument"];
}

@end

问题是相似的(实际上是相同的),简短的回答是不,你不能。我不敢相信。。你是认真的吗?你是说我必须在每个子类中复制这些私有变量的声明???那太不方便了。。一定还有别的办法你不仅要再声明一次。。您还在使用
@dynamic
业务第三次编写它。。这是将变量写入3次而不是1次@abbood好吧,如果它们是真正私有的,那么子类无论如何都不应该使用它们;)但是-我认为有一个超类+保护头的替代方案是可行的-这是苹果官方支持的(至少通过例子)。哦。。对不起,我把
private
protected
混淆了。。因此,我只想在我的superClass.m文件中声明
受保护的
变量,并让子类继承它,而无需重新声明它和这个动态业务。。这可能吗?我想知道如何像苹果公司在
UIgestureRecognitizerSubclass.h中那样实现这些东西。这些都是实例变量,objc没有类变量的概念。很高兴知道这一点。如果您需要与子类共享实例变量,@protected就是这样做的。这很好,但是@properties不是实例变量。最多-它们有这样的IVAR的备份存储,即使这样,您也无法比控制方法的可见性更好地控制这些IVAR的可见性。不需要类别。通过跳过
…(Protected)
@Regexident使其成为一个类扩展。这里的要点是,对于高个子类来说,protectedMethod是用于重写的。命名扩展(Protected)是一个完美的解决方案。
@implementation SomeSuperClass

-(void)somePrivateMethod:(NSString*)someArgument {
    ...
}
@interface SomeChildClass : SomeSuperClass
@interface SomeSuperClass (exposePrivateMethod)
-(void)somePrivateMethod:(NSString*)someArgument;
@end

@implementation SomeChildClass

-(void)doSomething {
    [super somePrivateMethod:@"argument"];
}

@end