使用 objc_getAssociatedObject() 时出现奇怪的 Swift 行为
Posted
技术标签:
【中文标题】使用 objc_getAssociatedObject() 时出现奇怪的 Swift 行为【英文标题】:Strange Swift behaviour when using objc_getAssociatedObject() 【发布时间】:2015-11-19 01:27:04 【问题描述】:可以通过将此代码放置在操场上来观察行为:
import Foundation
import ObjectiveC
class TestClass
var obj = TestClass()
let stringValue = "xyz"
let key = "def"
objc_setAssociatedObject(obj, key, stringValue, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC)
//let f = "f"
let returnedString = objc_getAssociatedObject(obj, key)
这有效并从objc_getAssociatedObject
调用返回“xyz”。
但是,如果您从 let f = "f"
行中删除评论。 objc_getAssociatedObject
调用现在返回 nil。
我对设置一个完全不相关的变量如何影响调用感到困惑。
有什么想法吗?
【问题讨论】:
你运行的是哪个 Xcode 版本? 我可以在 7.1.1 的操场上重现这一点,但不能在实际应用程序中重现。也许是游乐场的错误。 我正在考虑这个问题。此外,如果您将定义放在键和运行时调用之间,它会中断。如果将 let f = "f" 向上移动,它就可以正常工作。 我发布的代码是对我在单元测试中的代码的缩减。在测试中,我正在测试一些添加关联属性的代码。所以我想获取我存储的值来检查它是否正确。但是,即使我修改了我正在测试的代码以返回用于存储值的密钥,我也一直得到 nils。我知道这个值被存储了,因为其他代码后来很高兴地使用了这个值。所以我剪切粘贴到一个操场上,看看发生了什么,最后得到了上面的代码。 【参考方案1】:看起来像一个错误。
objc_... 方法是 Objective-C 运行时的一部分。它们不应该存在于 Swift 中。
这表明他们显然做到了。所以我的猜测是,当您设置启动运行时的方法时会发生一些事情,类似于在 NSUserDefaults 上调用 synchronize
。
编辑: This NSHipster article 解释说 ObjC 运行时确实在那里。
编辑 2:我尝试了一些实验,我会让你的问题变得更奇怪。将测试用例包装在对象内会产生相同的结果。但是将变量名称更改为下划线可以解决问题:
let _ = "f"
我敢打赌,分配一个变量会覆盖您手动设置的任何运行时关联。下划线只是告诉编译器你没有使用赋值的结果。
【讨论】:
如果将变量名称更改为下划线可以解决问题,这表明操场机制可能会干扰 Objective-C 运行时机制(或编译器将类注册到运行时)。 Xcode 无形地重写您的代码,添加日志功能来驱动结果侧边栏。当您分配给_
时,该特定代码行不会被重写。我建议提交错误报告(并在此处回复 # 以作记录)。
我不是 OP,但这就是我的暗示,但我仍然不确定该下划线的确切语义是什么。我问过的每个人都说“这意味着你没有使用变量”,但这对 Swift 编译器意味着什么?
见我上面的评论。我最初在单元测试中遇到了这个错误,并在试图弄清楚发生了什么时将其移到了操场上。我不知道它是否存在于应用程序中,因为我的原始代码实际上并未尝试检索该值。只有单元测试可以。以上是关于使用 objc_getAssociatedObject() 时出现奇怪的 Swift 行为的主要内容,如果未能解决你的问题,请参考以下文章
在使用加载数据流步骤的猪中,使用(使用 PigStorage)和不使用它有啥区别?
Qt静态编译时使用OpenSSL有三种方式(不使用,动态使用,静态使用,默认是动态使用)