以下是使用 objc @protected 指令 safe/legit 吗?
Is following use of objc @protected directive safe/legit?
我必须向 sub-类 公开一个私人 属性。
由于在 objc AFAIK 中没有 "protected properties" 这样的东西,我正在使用 @protected 指令来公开由编译器合成的相应 ivar。
此方法似乎有效,但是,我不确定我是否以某种不可取的方式影响了 属性 和 ARC 的合成?
我在这里使用弱 属性 来展示编译器如何强制我对 @protected 指令使用 __weak 修饰符,即看起来编译器知道这两个声明和他们之间的link。
超类 .h 文件
@interface Superclass : NSObject
{
@protected
SCNScene * __weak _scnScene;
}
@end
超类 .m 文件
@interface Superclass ()
@property (weak, nonatomic) SCNScene * scnScene;
@end
@implementation Superclass
........
@end
子类 .m 文件
@implementation Subclass
// Can use _scnScene just fine
_scnScene = .....
@end
在 class 声明的上下文中,protected
是实例变量的默认可见性,因此您的声明无效。其实就是下面的声明:
@interface Superclass : NSObject
@end
将与您发布的声明具有完全相同的效果,因为编译器会自动为声明的属性合成任何需要的 ivar,除非您自己声明它们。
是的,它可能会起作用。不要这样做。这是非常不灵活的。它强制您在 header 中声明 ivars,它仅适用于 ivars,并且不会让您对 read/write 控件有任何控制权(或让您创建自定义 getters/setters)。没有真正充分的理由再使用 @
访问控制(自 move to non-fragile ivars 以来就没有了,而且它们 以前 没那么有用)。
执行此操作的典型方法是使用带有类别的 +Protected
header。例如,您可以像这样创建 header 文件 Superclass+Protected.h
:
@interface Superclass (Protected)
@property (weak, nonatomic) SCNScene * scnScene;
@end
然后将其导入到任何允许访问 scnScene
的实施文件中。请注意,如果需要,您可以将其设为 readonly
,因此在内部它是可写的,但对于受保护的实现而言,它只是可读的,而对于 public,它是不可见的。
这比文字 "protected" 更灵活,因为您可以将此 header 导入到任何其他合适的实现中。所以它也可以等效于 C++ 的 "friend." 显然,命名文件并提供一些 header 注释有助于让调用者知道他们是否应该导入该文件。
对于任何关于这不强制执行访问控制的投诉(不是你做的,而是对任何人做的),@protected
也没有。 If I call valueForKeyPath:
, I can access protected ivars, too. ObjC 帮助您创建 "no trespassing signs" 以便呼叫者知道他们何时在不应该在的地方。它不会试图阻止程序访问它们自己的内存 space。 (这将是一个徒劳的目标;您始终可以使用任何允许原始内存访问的语言读取私有变量和调用私有函数;访问控制的要点是帮助调用者编写正确的代码,而不是阻止他们做任何事情。)
我必须向 sub-类 公开一个私人 属性。 由于在 objc AFAIK 中没有 "protected properties" 这样的东西,我正在使用 @protected 指令来公开由编译器合成的相应 ivar。
此方法似乎有效,但是,我不确定我是否以某种不可取的方式影响了 属性 和 ARC 的合成?
我在这里使用弱 属性 来展示编译器如何强制我对 @protected 指令使用 __weak 修饰符,即看起来编译器知道这两个声明和他们之间的link。
超类 .h 文件
@interface Superclass : NSObject
{
@protected
SCNScene * __weak _scnScene;
}
@end
超类 .m 文件
@interface Superclass ()
@property (weak, nonatomic) SCNScene * scnScene;
@end
@implementation Superclass
........
@end
子类 .m 文件
@implementation Subclass
// Can use _scnScene just fine
_scnScene = .....
@end
在 class 声明的上下文中,protected
是实例变量的默认可见性,因此您的声明无效。其实就是下面的声明:
@interface Superclass : NSObject
@end
将与您发布的声明具有完全相同的效果,因为编译器会自动为声明的属性合成任何需要的 ivar,除非您自己声明它们。
是的,它可能会起作用。不要这样做。这是非常不灵活的。它强制您在 header 中声明 ivars,它仅适用于 ivars,并且不会让您对 read/write 控件有任何控制权(或让您创建自定义 getters/setters)。没有真正充分的理由再使用 @
访问控制(自 move to non-fragile ivars 以来就没有了,而且它们 以前 没那么有用)。
执行此操作的典型方法是使用带有类别的 +Protected
header。例如,您可以像这样创建 header 文件 Superclass+Protected.h
:
@interface Superclass (Protected)
@property (weak, nonatomic) SCNScene * scnScene;
@end
然后将其导入到任何允许访问 scnScene
的实施文件中。请注意,如果需要,您可以将其设为 readonly
,因此在内部它是可写的,但对于受保护的实现而言,它只是可读的,而对于 public,它是不可见的。
这比文字 "protected" 更灵活,因为您可以将此 header 导入到任何其他合适的实现中。所以它也可以等效于 C++ 的 "friend." 显然,命名文件并提供一些 header 注释有助于让调用者知道他们是否应该导入该文件。
对于任何关于这不强制执行访问控制的投诉(不是你做的,而是对任何人做的),@protected
也没有。 If I call valueForKeyPath:
, I can access protected ivars, too. ObjC 帮助您创建 "no trespassing signs" 以便呼叫者知道他们何时在不应该在的地方。它不会试图阻止程序访问它们自己的内存 space。 (这将是一个徒劳的目标;您始终可以使用任何允许原始内存访问的语言读取私有变量和调用私有函数;访问控制的要点是帮助调用者编写正确的代码,而不是阻止他们做任何事情。)