在 Objective-C 中完成受保护属性的解决方法

Posted

技术标签:

【中文标题】在 Objective-C 中完成受保护属性的解决方法【英文标题】:Workaround to accomplish protected properties in Objective-C 【发布时间】:2012-06-18 07:51:38 【问题描述】:

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

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

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 的 extension 工作,并允许我们将属性标记为 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

【问题讨论】:

如果我将“ClassA_protected.h”导入到仅访问 ClassB 的 ViewController 类中怎么办?我仍然可以通过主类中的 ClassB 对象访问 ClassA 的受保护属性(这里是 ViewController 类)。 【参考方案1】:

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

【讨论】:

受保护的变量不应该只能由类本身及其子类访问吗?我仍然可以从其他类中读取变量,因为您将其设为只读,我认为这会使受保护的变量规则无效【参考方案2】:

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

而且,默认已经被保护了。

【讨论】:

在某些情况下,属性是有益的。例如KVO 合规性、在单个位置设置/获取属性的能力(自定义 setter/getter)、脆弱的基类问题等。【参考方案3】:

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

_myProtectedInt

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

【讨论】:

【参考方案4】:

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

ClassB.h

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

ClassB.m

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

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

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

【讨论】:

以上是关于在 Objective-C 中完成受保护属性的解决方法的主要内容,如果未能解决你的问题,请参考以下文章

将受保护的 Objective-C 实例变量公开给子类

Objective-C 中的受保护方法

ES6 类中的受保护属性(使用符号?)

实体框架 CTP4 代码优先:映射受保护的属性

PHP 受保护的类和属性,受谁保护?

受保护的内部属性与受保护的属性和 Resharper