【问题标题】:Using hidden properties vs. private iVars使用隐藏属性与私有 iVar
【发布时间】:2014-01-07 08:13:27
【问题描述】:

这个问题专门针对静态库/框架;换句话说,其他人最终会接触到的代码。

我相当精通属性,因为我在 iOS 6 发布时就开始了 iOS 开发。我使用了在接口扩展中声明的隐藏属性来完成我所有的“私有”属性工作,包括在我不希望其他人修改的面向公众的属性上使用readonly,以及在接口扩展中使用readwrite

重要的是我确实希望其他使用这些静态库/框架的人在我不允许的情况下访问这些属性,如果我允许他们也不编写这些属性阅读它。

我早就知道他们理论上可以创建自己的接口扩展,并让我的readonly 属性readwrite 自己,或者猜测隐藏属性的名称。

如果我想阻止这种情况,我应该使用带有@private 标记的 ivars 和直接声明的 ivars 吗?这样做有潜在的失败吗?它是否真的让我获得了额外的安全措施,或者它是一个红鲱鱼?

【问题讨论】:

  • 您无法阻止在运行时访问该属性。比较stackoverflow.com/questions/4777165/…
  • 我很清楚,Obj-C 运行时的强大功能带来了一些安全“风险”。我更多地想到的是随便的黑客,而不是完全敬业的黑客。

标签: ios objective-c properties ivar


【解决方案1】:

在 ARC 下,属性而非实例变量支持的唯一模式是 copy - 因此,如果您需要 copy,请使用属性。

如果您在 @implementation 部分声明您的私有实例变量:

@implementation MyClass
{
   // private instance vars
}

那么从课堂外访问它们需要付出很大的努力。正如您所说,访问“私有”属性只需猜测其名称 - 或使用告诉您的库调用。

为了安全值得吗? YMMV。但无论如何,这是一种很好的编码习惯。

附录

正如评论线索显示的那样,关于我使用认真的努力的讨论很多。

首先让我们明确一点:Objective-C 属于 C 语言家族,它们都允许程序员在语言中选择任何东西[*] - 这些不是如果您想要强类型、访问限制等,请选择语言。您的代码中。

第二,“努力”不是绝对的衡量标准!所以也许我应该选择“明显”这个词来限定它而不是“严重”。要访问私有属性只需要使用标准方法调用,其中对象的类型为id - 代码中几乎没有线索表明被调用的方法是隐藏的。要访问私有变量需要 API 调用(运行时函数或 KVC 调用)或一些指针操作 - 生成的代码看起来与标准变量赋值完全不同。所以它更明显

也就是说,除了需要copy 的用途外,在 ARC 下,当私有实例变量可以使用时,没有充分的理由使用私有属性。对于私有变量fred 比较:

self.fred = 42;   // property access, may involve a call (if not optimised out)
_fred = 42;       // common way to bypass the accessors and get at the underlying var
fred = 42;        // direct access

任你选择,没有正确答案,但也没有错误 - 这是意见的领域(这当然是意见 ;-))。我经常会选择最后一个,私有变量——干净且简单。但是@RobNapier 在他的回答中更喜欢使用属性。


[*] 注意:一旦你考虑链接到外部代码,比如说用汇编程序编写的,所有的赌注都是任何语言。此时,您必须查看“硬件”(真实或虚拟)和/或“操作系统”以提供保护。

【讨论】:

  • 你能为我澄清一下“认真的努力”吗?我们是否在谈论可以在代码中进行的 objc 运行时调用以将它们拉出并修改它们?我意识到 Obj-C 不是一种特别安全的语言,所以我想我想澄清一下它所涉及的工作量。
  • @JoelFischer - 一些运行时函数,禁用 ARC,一两个演员。但正如你所说,它是 (Obj-)C 所以一切皆有可能。如果您想要安全代码的语言支持,请不要使用基于 C 的语言!
  • @CRD 不太确定“认真的努力”,因为一个简单的 KVC 调用可以修改任何 ivar。
  • @jlehr 但是假设你接受他的建议并在实现块中声明它们,那么“认真的努力”就会变成核弹class_copyIvarList()
  • @CodaFi 在这里可能不完全清楚。关键是 class_copyIvarList() 将为您提供 ivars 列表(包括它们的名称和类型)。访问它们就像 object_getInstanceVariable() 一样简单。它比访问您的“隐藏”属性需要大约 45 秒的时间。这里没有胜利。
【解决方案2】:

您应该在此处使用私有(“隐藏”)属性。不存在“安全”风险。这种情况下的“攻击者”是调用者。调用者可以完全访问进程中的所有内存。她可以访问您想要访问的框架中的任何内容,并且您绝对无法做任何事情来阻止它(您也不应该这样做)。在任何语言中都是如此。如果您知道自己在做什么,您也可以绕过 C++ 中的“private:”指定。这一切都只是一天结束时的记忆。

保护你自己或你的框架免受调用者的伤害不是你的工作。你们都有相同的目标:正确的程序行为。您的目标是保护来电者免受自己的伤害。让他们很难错误地使用你的框架,并且很容易正确地使用它。

因此,您应该使用生成最正确代码的工具。而那个工具就是properties,除了init和dealloc之外,避免直接访问ivar。

【讨论】:

  • 假设此代码不是开源的,并且是专有的并受许可协议保​​护。我意识到在 Objective-C 中没有什么是安全的,但它仍然有利于公司保持相对安全的东西免受随意的黑客攻击。根据您(和其他人)所说的,听起来私有 ivars 确实更安全,但对于中间黑客来说肯定不安全。所以它变成了“稍微更安全”与“肯定更正确”。
  • 您可能对以前的讨论感兴趣:stackoverflow.com/questions/2334072/…。将您的代码向您发送给的人隐藏是一场失败的游戏和金钱的损失。专注于使其代码更好,维护成本更低。直接 ivar 访问不会为您提供任何有用的安全性来对抗您的库中的某人,但它会引入错误,您将不得不花钱和善意来解决。
  • @RobNapier - 假设 ARC,对于 private “变量”,不包括属性的 copy 选项,您能否总结一下为什么您认为选择“是属性,并且除了 init 和 dealloc 之外,避免直接访问 ivar”?只是好奇。
  • @CRD,请参阅stackoverflow.com/a/15644838/97337,了解我对此的讨论之一。它归结为可维护性。直接 ivar 访问使得在存在任何实际需要访问器的情况下验证代码的正确性变得非常困难(这很常见)。复制只是几种模式之一。但复制是一个很好的例子。您如何根据“使用 ivars 除非属性为 copy”的规则进行审核?你如何跟踪哪些是哪些?要求开发人员检查每一行代码的头文件是通往 bug 的必经之路。一致性保护我们。
  • @RobNapier - 谢谢。我理解你的论点,虽然我可能不同意 ;-) 但这是另一个问题。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-08-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多