【问题标题】:What data type do ivars for primitive properties have?原始属性的 ivars 有哪些数据类型?
【发布时间】:2017-01-25 22:18:12
【问题描述】:

我之所以问,是因为我正在涉足一些复杂的块代码,我没想到下面的代码可以正常工作。

假设我们有一个 BOOL 属性,如下所示:

@property (nonatomic, assign) BOOL isCancelled;

它是自动合成的,没有自定义 getter,没有 setter,没有显式 ivar。

然后,有这段代码......完美运行

dispatch_async(queue, ^{
    id result = block(&_isCancelled);
    if (!_isCancelled) { ... }
}

但是,我希望它适用于 block() 调用,但不适用于 if,我认为它会捕获 _isCancelled 的值并将其保持为常量,而不是让它在整个执行过程中发生变异。尽管如此,在运行时,_isCancelled 的值在块内部/外部始终是一致的,就好像它实际上是 BOOL *

谁能解释这是怎么回事?

【问题讨论】:

  • 在给定的代码中实际上没有使用任何属性,_isCancelled 只是一个普通的 ivar 尽管隐式声明。
  • 同意,但因为它没有明确声明,我可以假设它被声明为指针而不是原语。这可以解释这种行为(除非我遗漏了什么)
  • 属性的类型与后备ivar的类型相同。声明属性BOOL isCancelled 意味着将合成一个ivar BOOL _isCancelled。就是这样。
  • 那么,为什么 _isCancelled 不在块内保持 const 呢?
  • @CatalinaM 为什么会这样?它是一个实例变量,而不是局部变量。该块实际上正在捕获self。不是伊瓦尔。 _isCancelled 实际上意味着 self->_isCancelled。见stackoverflow.com/questions/5807022/…

标签: objective-c properties ivar


【解决方案1】:

当声明属性BOOL cancelled 时,自动合成的ivarBOOL _isCancelled。这是一个原始变量,而不是指针。

但是,当一个块在捕获 ivar 时,它实际上是在捕获 self,而不是 ivar 本身。读取 ivar _isCancelled 实际上意味着读取 self->_isCancelled

因此,除非您先将 ivars 保存到局部变量中(例如 BOOL isCancelled = _isCancelled),否则不会按值捕获 ivars。

更多信息请参见Block automatic retaining, does it affect even to ivars in self?

【讨论】:

    【解决方案2】:

    TL;DR:与属性相同的类型。

    所有对象指针和原始类型都是标量值 - 即奇异值。它们都需要存储在内存中的某个地址,因此它们都有自己的内存地址。

    通过传递 &_isCancelled,您将传递BOOL 变量的地址,因此block() 已“泄露秘密” " - 即BOOL 的位置 - 所以它可以更新它。然后,您将检查 _isConnected 的结果 实际 值。这适用于原始类型(标量)和对象指针(也是标量)。

    它是否是属性无关紧要。

    【讨论】:

    • 我也是这么想的。我期待 _isCancelled 在块内是不可变的(因为它将范围内的所有变量都视为 const,因此它总是具有在评估块时具有的值)。但是,我怀疑这种行为与 _isConnected 是全局而不是局部范围有关。
    • 您传入的值 is const - 它是 BOOL 的地址。除了代码块从字面上改变该地址的一些位之外,没有任何变化。在块内部,变量不是 BOOL,它是指向 BOOL 的指针。
    • 我的问题在于内部块执行之后的 if 。但是,我现在明白 self 实际上是保留的,即使没有直接引用。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2010-09-30
    • 2019-02-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-01-21
    • 2012-11-28
    相关资源
    最近更新 更多