39

我一直在尝试找到一种解决方法来在 Objective-C 中声明 @protected 属性,这样只有层次结构中的子类才能访问它们(只读,不能写)。我读到没有记录的方法可以做到这一点,所以我想到了这个解决方法,我想问问 StackOverflow 对此的看法。

层次结构顶部的每个自定义类都包含三个类,一个实现和两个接口。让我们为它们命名:

ClassA.h
ClassA_protected.h
ClassA.m

那么这个 ClassA 的任何子类都会像往常一样:

ClassB.h
ClassB.m

首先,我创建了接口ClassA.h,在其中声明了一个受保护的 int 变量,因此 ClassA 的任何子类都可以访问它:

@interface ClassA : NSObject{
    @protected
    int _myProtectedInt;
}
@end

下一步是我正在谈论的解决方法。但是,一旦您阅读它,您会发现它非常简单。我声明了第二个名为ClassA_protected.h的接口,它实际上是 ClassA.h 的扩展,并允许我们将属性标记为readonly

#import "ClassA.h"
@interface ClassA ()
@property (nonatomic , readonly) int myProtectedInt;
@end

准备受保护层次结构的最后一步是在ClassA.m中声明它的实现,我们只合成我们的属性:

#import "ClassA_protected.h"
@implementation ClassA
@synthesize myProtectedInt = _ myProtectedInt;
@end

这样,每个需要成为ClassA.h子类的类都将导入ClassA_protected.h。因此,像ClassB.h这样的孩子将如下所示:

#import "ClassA_protected.h"
@interface ClassB : ClassA
@end

以及从ClassB.m的实现中访问此属性的示例:

@implementation ClassB
-(void) method {
    //edit protected variable 
    _myProtectedInt= 1;

    //normal access
    self.muProtectedInt;
}
@end
4

4 回答 4

20

当然,这很好用。UIGestureRecognizer例如,Apple 在课堂上使用了相同的方法。子类必须导入附加UIGestureRecognizerSubclass.h文件并覆盖该文件中声明的方法。

于 2012-06-15T09:05:59.317 回答
6

对于简单的“属性”,只需使用 ivar 代替。这与所有实际用途的属性一样好。

此外,默认值已经受到保护。

于 2013-06-10T08:00:26.493 回答
3

如果你征求意见,这是我的:如果有人决定改变你的

_myProtectedInt

无论如何,他可能会成功,因为使用 Objective-C 运行时绝对有可能。除此之外,您的解决方案还可以。

于 2012-06-15T09:06:18.163 回答
0

仅在实现中导入受保护的标头。例如

B类.h

#import "ClassA.h"
@interface ClassB : ClassA
@end

B类.m

#import "ClassA_protected.h"
@implementation ClassB
@end

在框架中,受保护的标头应标记为项目,因此它不包含在框架的公共标头中。Apple 通常使用后缀 _Internal.h 作为其受保护的方法。

对于初始化或覆盖延迟加载的 get 属性,您需要直接访问 @proteced ivar,但是对于您的使用,最好将属性重新声明为 readwrite,然后您可以利用 setter 的任何功能,例如原子性.

于 2018-07-08T10:23:04.987 回答