Sti*_*Sti 38 null memory-management optional ios swift
someFunction(completion: { [weak self] in
self?.variable = self!.otherVariable
})
Run Code Online (Sandbox Code Playgroud)
这总是安全吗?我self
在语句的开头访问了可选项,并且我个人认为如果self
是,那么该语句的第二部分将永远不会被执行nil
.这是真的?如果self
确实如此nil
,第二部分永远不会发生?self
在这一行代码中,它永远不会被"填充"?
Mar*_*n R 25
"Swift编程语言"中的可选链接给出了以下示例:
Run Code Online (Sandbox Code Playgroud)let john = Person() // ... let someAddress = Address() // ... john.residence?.address = someAddress
其次是(强调补充):
在此示例中,尝试设置john.residence的地址属性将失败,因为john.residence目前为零.
赋值是可选链接的一部分,这意味着不会对=运算符右侧的代码进行求值.
适用于您的案例:In
self?.variable = self!.otherVariable
Run Code Online (Sandbox Code Playgroud)
如果是,则不评估右侧.因此,你的问题的答案self
nil
如果自我确实是零,第二部分永远不会发生?
是是的".关于第二个问题
在这一行代码中,自我可能永远不会被"掏空"吗?
我最初的假设是,一旦self
确定了!= nil
,self!
在整个评估声明中就会有一个强有力的参考,这样就不会发生这种情况.但是(正如@Hamish指出的那样),这并不能保证.Apple工程师Joe Groff 在Swift论坛中的确认操作顺序中写道:
这不保证.版本可以优化为在此之前发生,在最后一次正式使用强引用之后的任何时刻.由于为了评估左侧而加载的强引用
weakProperty?.variable
后来没有使用,因此没有任何东西可以保持它存活,所以它可以立即释放.
如果getter中的变量有任何副作用导致被引用的对象weakProperty
被释放,则输出弱引用,那么这将导致右侧的force-unwrap失败. 你应该使用if来测试弱引用,并引用由该引用绑定的强引用if let
dfr*_*fri 16
正如@Hamish在下面的评论中指出的那样,Swift编译工程师Joe Groff描述了无法保证在RHS评估期间持有强有力的参考[ 强调我的 ]
确认操作顺序
Rod_Brown:
嗨,您好,
我想知道一个弱变量的访问类型的安全性:
Run Code Online (Sandbox Code Playgroud)class MyClass { weak var weakProperty: MyWeakObject? func perform() { // Case 1 weakProperty?.variable = weakProperty!.otherVariable // Case 2 weakProperty?.performMethod(weakProperty!) } }
对于上面两种情况,Swift是否保证
weakProperty
可以在这些位置展开力?我很好奇Swift在可选链接期间对访问的保证例如,
weakProperty!
如果可选链接首先确定该值已经是非链接,那么访问器只能保证触发nil
吗?此外,是否保证在此评估期间保留弱对象,或者弱变量是否可能在可选访问和被调用方法之间解除分配?
Joe_Groff:
这不保证.版本可以优化为在此之前发生,在最后一次正式使用强引用之后的任何时刻.由于为了评估左侧而加载的强引用
weakProperty?.variable
后来没有使用,因此没有任何东西可以保持它存活,所以它可以立即释放.如果getter中的变量有任何副作用导致被引用的对象weakProperty
被释放,则nil
输出弱引用,则会导致右侧的force-unwrap失败.你应该使用if来测试弱引用,并引用if let绑定的强引用:Run Code Online (Sandbox Code Playgroud)if let property = weakProperty { property.variable = property.otherVariable property.performMethod(property) }
这应该更安全,也更有效,因为弱引用被加载和测试一次而不是四次.
考虑到乔Groff上面回答的回答,我之前的回答没有实际意义,但我会把它留在这里作为一个可能有趣(虽然失败)的旅程进入Swift编译器的深度.
我将根据我对@appzYourLife的评论得出这个答案:删除的答案:
这是纯粹的推测,但考虑到许多经验丰富的Swift核心开发人员与C++:Boost lib之间的密切联系,我会假设
weak
在表达式的生命周期中,引用被锁定为强大的引用,如果这指定/变异某事inself
,就像明确使用std::weak_ptr::lock()
的C++对应物一样.
让我们看一下您的示例,其中self
已经被weak
引用捕获,而不是nil
在访问赋值表达式的左侧时
self?.variable = self!.otherVariable
/* ^ ^^^^^-- what about this then?
|
\-- we'll assume this is a success */
Run Code Online (Sandbox Code Playgroud)
我们可以weak
在Swift运行时查看(Swift)引用的基本处理,swift/include/swift/Runtime/HeapObject.h
具体来说:
Run Code Online (Sandbox Code Playgroud)/// Load a value from a weak reference. If the current value is a /// non-null object that has begun deallocation, returns null; /// otherwise, retains the object before returning. /// /// \param ref - never null /// \return can be null SWIFT_RUNTIME_EXPORT HeapObject *swift_weakLoadStrong(WeakReference *ref);
这里的关键是评论
如果当前值是已经开始释放的非null对象,则返回null; 否则,在返回之前保留该对象.
由于这是基于后端运行时代码注释,它仍然有点推测,但我会说上面暗示当试图访问weak
引用指向的值时,确实会将引用保留为生命周期中的强引用电话("......直到返回").
为了尝试从上面赎回"有点推测"的部分,我们可能会继续深入研究Swift如何通过weak
引用处理值的访问.从下面的@idmean:s评论(研究生成的 SIL代码,例如OP:s),我们知道该swift_weakLoadStrong(...)
函数被调用.
所以我们首先考察swift_weakLoadStrong(...)
函数的实现,swift/stdlib/public/runtime/HeapObject.cpp
然后看看我们从那里得到的东西:
Run Code Online (Sandbox Code Playgroud)HeapObject *swift::swift_weakLoadStrong(WeakReference *ref) { return ref->nativeLoadStrong(); }
我们找到了from nativeLoadStrong()
方法的实现WeakReference
swift/include/swift/Runtime/HeapObject.h
Run Code Online (Sandbox Code Playgroud)HeapObject *nativeLoadStrong() { auto bits = nativeValue.load(std::memory_order_relaxed); return nativeLoadStrongFromBits(bits); }
从同一个文件中,执行nativeLoadStrongFromBits(...)
:
Run Code Online (Sandbox Code Playgroud)HeapObject *nativeLoadStrongFromBits(WeakReferenceBits bits) { auto side = bits.getNativeOrNull(); return side ? side->tryRetain() : nullptr; }
继续沿着调用链,tryRetain()
是一种方法HeapObjectSideTableEntry
(对于对象生命周期状态机是必不可少的),我们发现它的实现方式swift/stdlib/public/SwiftShims/RefCount.h
Run Code Online (Sandbox Code Playgroud)HeapObject* tryRetain() { if (refCounts.tryIncrement()) return object.load(std::memory_order_relaxed); else return nullptr; }
类型的tryIncrement()
方法的实现RefCounts
(这里通过它的一个实例调用typedef
:ed的特化)可以在上面的同一个文件中找到:
Run Code Online (Sandbox Code Playgroud)// Increment the reference count, unless the object is deiniting. bool tryIncrement() { ... }
我相信这里的评论足以让我们使用这个方法作为终点:如果对象没有去除(我们上面假设它没有,因为lhs
OP:s例子中的赋值被认为是成功的),对象的(强)引用计数将增加,并且HeapObject
指针(由强引用计数增量支持)将传递给赋值运算符.我们不需要研究如何在赋值结束时最终执行相应的引用计数递减,但现在知道超出推测,与weak
引用相关联的对象将在赋值的生命周期中保留为强对象,因为它在左手边访问它时没有被释放/解除分配(在这种情况下,它的右侧将永远不会被处理,如@MartinR:s答案中所述).
归档时间: |
|
查看次数: |
2395 次 |
最近记录: |