【问题标题】:Is following use of objc @protected directive safe/legit?使用 objc @protected 指令是否安全/合法?
【发布时间】:2017-08-10 08:33:24
【问题描述】:

我必须向子类公开私有属性。 由于 objc AFAIK 中没有“受保护的属性”之类的东西,我使用 @protected 指令来公开编译器合成的相应 ivar。

这种方法似乎有效,但是,我不确定我是否以某种不可取的方式影响了属性和 ARC 的合成?

我在这里使用了一个弱属性来显示编译器如何强制我将 __weak 修饰符与 @protected 指令一起使用,即编译器似乎知道这两个声明以及它们之间的链接。

超类 .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

【问题讨论】:

  • P.S.当然,通过在子类中直接使用 ivar (_scnScene),我会绕过 Super 可能拥有的任何 setter/getter,但我更关心 ARC 等问题。
  • @protected 不会干扰 ARC,它定义了 ivars 的可见性。

标签: objective-c properties protected


【解决方案1】:

是的,它可能会起作用。不要这样做。这是非常不灵活的。它强制您在标头中声明 ivars,它仅适用于 ivars,并且不会让您对读/写控件进行任何控制(或让您创建自定义 getter/setter)。真的没有充分的理由再使用@ 访问控制(自从move to non-fragile ivars 之后就没有了,而且它们之前那么没用)。

执行此操作的典型方法是使用带有类别的 +Protected 标头。例如,您可以像这样创建一个头文件Superclass+Protected.h

@interface Superclass (Protected)
@property (weak, nonatomic) SCNScene * scnScene;
@end

然后将其导入任何允许访问scnScene 的实现文件中。请注意,如果您愿意,可以将其设为 readonly,因此在内部它是可写的,但对于受保护的实现,它只能读取,而对于公众,它是不可见的。

这比字面的“受保护”更灵活,因为您可以将此标头导入到任何其他适当的实现中。所以它也可以相当于 C++ 的“朋友”。显然,命名文件并提供一些标头 cmets 有助于让调用者知道他们是否应该导入此文件。

对于任何关于这不强制执行访问控制的投诉(不是你做了任何,但对于任何这样做的人),@protected 也没有。 If I call valueForKeyPath:, I can access protected ivars, too. ObjC 可帮助您创建“禁止擅闯标志”,以便呼叫者知道他们何时在不该出现的地方。它不会试图阻止程序访问它们自己的内存空间。 (这将是一个徒劳的目标;您始终可以使用任何允许原始内存访问的语言读取私有变量并调用私有函数;访问控制的目的是帮助调用者编写正确的代码,而不是阻止他们做任何事情。)

【讨论】:

  • 感谢您的回复。是的,我知道有两个 .h 文件的解决方案,即 Apple 的 UIGestureRecognizer 方法;p,但只是认为这可能是一种更快的方法。我同意在这种情况下使用 @protected 似乎只会增加更多风险。我个人会选择在 .h 文件中直接将超类属性公开为只读,并以这种方式在子类中使用它。这对我来说只是感觉最干净和简单的解决方案。 (我将把这个问题留几个小时,看看是否有其他人想说点什么,如果没有其他人愿意,则将您的答案标记为已接受)
【解决方案2】:

在类声明的上下文中,protected 是实例变量的默认可见性,因此您的声明无效。其实就是如下声明:

@interface Superclass : NSObject
@end

将具有与您发布的声明完全相同的效果,因为编译器会自动为声明的属性合成任何所需的 ivars,除非您自己声明它们。

【讨论】:

  • 感谢您的回复。这也是我对私有(在 .m 文件中定义)属性的行为的期望。
  • (在我完成之前在上面发布了我的上一条评论,所以在这里完成)这正是我对私有(在 .m 文件中定义)属性的行为的期望,这就是我实现我的方式最初的超类和子类。但是,我无法访问子类中的任何超级 setter/getter 或 ivars,因此我开始寻找另一种解决方案。也许它取决于编译器版本,它在以前的(或更新的版本)中工作。我将 LLVM 7.1 与 Xcode 7.3 一起使用,显然它不允许子类访问超级“私有”属性/相应的 ivars。
  • 对于在 Objective-C 类扩展中声明的属性的 ivars,可见性默认为 private
猜你喜欢
  • 2015-10-14
  • 1970-01-01
  • 1970-01-01
  • 2012-08-08
  • 1970-01-01
  • 1970-01-01
  • 2014-06-15
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多