如何解决我们可以在将 Objc 对象从 void*“桥接”到 UIKit 对象之前检查它是否已被释放?
我正在使用 QTouchposeApplication 库(特别是来自 TRTouchposeApplication
分支的 develop
类)。
master
分支中的执行路径之一发生崩溃,作者在 develop
分支中修复了它们。但是,其中一个崩溃仍然存在。
假设我们有一个 CF
-dictionary,它存储 UITouch
个对象而不保留它们:
// Dictionary of touches being displayed. Keys are UITouch pointers and values are UIView pointers that visually represent
// the touch on-screen. (A cfmutabledictionaryRef is used because NSDictionary requries its keys to conform to the
// NScopying protocol and UITouch doesn't. We don't need to retain either the UITouch or UIView instances because UITouch
// objects are persistent throughout a multi-touch sequence,and the UIViews are retained by their superview.)
cfmutabledictionaryRef _touchDictionary;
我们像这样将 UITouch
添加到字典中:
CFDictionarySetValue(_touchDictionary,(__bridge const void *)(touch),(__bridge const void *)(someUIView));
然后在某个时刻 UITouch
被系统释放(我在我的项目中使用 ARC)。
因此,当我们尝试“展开”触摸时,它会崩溃。我收到一条带有 Xcode Address Sanitizer 的消息 -[UITouch retain]: message sent to deallocated instance
:
所以崩溃的原因是我们将 ARC 对象存储为 void*
,所以如果这个对象被释放,__bridge
就会崩溃。
我见过__bridge
、__bridge_transfer
、__bridge_retained
,但没有看到像bridge_TRY
这样的东西。
为了给这个崩溃写一个补丁,我想知道:
- 在这种情况下,我们能否以某种方式“安全地桥接”并获得结果
UITouch = nil
,如果触摸被解除分配。 - 我们能否以某种方式订阅“UITouch”解除分配,以便我们从
UITouch
中删除相应的CFDictionary
之前触摸对象将被删除并且指针无效?立> - 还有其他方法可以解决这个问题吗?
解决方法
如果您需要在键或值处存储弱指针,则需要使用 NSMapTable
而不是字典
在第 83 行中,您使用循环 for
来检查每个字典值,但在第 91 行中您更改字典大小。所以最好在第 77 行添加其他 outputDictionary
,这将等于 _touchDictionary
,并在第 91 行从 outputDictionary
中删除数据,并在第 95 行将 _touchDictionary = outputDictionary
设置回来。
这样更安全
,看这段代码,我相信字典应该保留触摸和视图。内存管理的简单规则是“保留你关心的,当你不再关心时释放”。很少有理由依赖其他对象为您保留内容。
“非保留”CFDictionaries 的优点是它们允许您存储对保留和释放不响应的内容(例如,分配的内存)。但通常,您应该使用标准回调对它们启用正常的内存管理。而不是这样:
_touchDictionary = CFDictionaryCreateMutable(NULL,10,NULL,NULL);
使用:
_touchDictionary = CFDictionaryCreateMutable(NULL,&kCFTypeDictionaryKeyCallBacks,&kCFTypeDictionaryValueCallBacks);
然后字典会为你保留它的键和值。
在手势完成后,请务必小心按住 UITouch。 docs forbid this:
触摸对象在多点触控序列中持续存在。您可以在处理多点触控序列时存储对触控的引用,只要在序列结束时释放该引用即可。 如果您需要在多点触控序列之外存储有关触控的信息,请从触控复制该信息。
但我认为您不一定做错了。崩溃发生在您移除触摸的点上,我认为这是在序列的末尾。
只是谈谈您的一些其他想法:
在这种情况下,我们能否以某种方式“安全地桥接”并得到结果 UITouch = nil,如果触摸被释放。
是的,但这需要弱指针,这可能是一个太大的变化。 Cy-4AH 的 NSMapTable 建议可以做到这一点,但您需要在整个代码中进行更改。
我们可以以某种方式订阅“UITouch”释放
是的,但不要。 :D 你可以附加一个 associated object ,它有自己的 dealloc
,当它所附加的对象被释放时它会触发,然后你可以做一些响应。但这对于这个问题 IMO 来说太过分了。如果您需要示例,请参阅 PMKVObserverDeallocSpy。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。