具有本地方法作用域的实例变量

3
在一个方法中创建一个本地作用域变量,使其在类实例的生命周期内存在,这种做法是否可行?我不能使用static,因为它会被所有类实例共享,这样不好。实际上,我想通过使一个实例变量只能被类中的一个特定方法访问来保护它。
我认为这似乎是不可能的,但我想问一下,因为这会帮助很多人。
更新 所以,我将@dasblinkenlight的答案标记为正确的(确实是这样)。尽管@joshcaswell在评论中提供了更好的答案参考,这是Richard J. Ross III的关联引用实际实现。这提供了一种更简单的方法来关联引用而不必深入运行时(因为他已经为您做了)。如果我在最初的搜索中发现了这个答案,我就不会首先提出这个问题。但是我没有,所以我提出了这个问题。
为什么要这样做? 今天我看到了Brent Simmons的一篇文章,题为为什么使用关联对象是一种hack?,这直接涉及到我为什么需要首先这样做的问题(@bbum和@GabrielePetronella问了这个问题)。在我的与@dasblinkenlight的讨论中,我解释了我想要保护一个懒惰实例化的iVar不被直接访问,除了它的构造方法。这样做的最佳方式是隐藏iVar,使所有其他类方法都无法访问它,因此只能通过其构造方法访问它。当然,您可以依赖命名约定(即:_lazyiVar)来提醒您不要直接访问它,但这是一种相当脆弱的保护形式(而且我过去确实做过这件事)。使用关联引用确实是一种hack,您应该质疑直接访问运行时的技术,但在这种情况下,我更喜欢这种hack,因为它通过保护我的懒惰实例化变量使我的代码更不容易崩溃。

1
一个实例变量? - bbum
@bbum 本地方法作用域 - Gabriele Petronella
1
@bbum 哦,我也一样。 :D - Gabriele Petronella
我认为这与ObjC ivar scoped method variables相同,针对此问题Richard J. Ross III编写了一个非常巧妙但有些复杂的解决方案。 - jscs
你之所以这样做的解释表明你通常是在对象内部访问 ivars,而不是使用它们的访问器。仅在 init 和 dealloc 中使用访问器可以通过使对 ivars 的所有访问都变得可疑(因此不易受损),而不是试图记住何时适用和不适用来避免这种麻烦。开发高度一致的编码实践比设计复杂的解决方案更好。 - Rob Napier
显示剩余3条评论
1个回答

4
您是正确的,这是不可能的:本地变量不能超出其定义的范围。您可以通过类扩展添加类似“私有”的实例变量,但这些变量将对所有方法的实现都可见,而不仅仅是单个方法。
您还可以使用关联引用来模拟添加实例变量,但这需要直接与运行时交互。这些引用也将对所有方法可见,但您可以通过使它们的静态ObjectTagKey局部化到您的方法中来“隐藏”它们。

是的,使用关联引用可能有效,但对于我想实现的目标来说太过繁琐。我正在懒惰地实例化变量,并认为如果我可以强制其他方法调用使用该方法而不是直接访问变量,那将是很棒的。 - Aaron Hayman
如果ivar在类扩展中(即不在头文件中),那么直接访问它的唯一代码就是你自己的代码。 - Sergey Kalinichenko
我觉得你误解了。我的意思是“强制同一类中的其他方法”使用构造方法而不是直接访问iVar。这将确保在未实例化iVar时,我不会意外地直接访问它(例如,如果我过一段时间后回到代码)。除非我绝对需要使它们公开,否则所有我的iVars都在@implementation中私下列出...这是非常罕见的。 - Aaron Hayman
@AaronHayman 我明白了。在这种情况下,您可以为变量取一个与实际名称相关的特殊名称,但同时指示该变量是惰性初始化的。例如,如果您的变量存储 maxSize,则称变量为 _lazyInitMaxSize,并仅在 maxSize 方法中使用它。维护代码的人员(包括您自己)应该能够猜出他们不应直接访问该变量。 - Sergey Kalinichenko

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接