如何给UIView扩展便捷的UITapGestureRecognizer并消除Xcode警告?
消除UIView手势扩展中的UnsafeRawPointer警告
问题根源
你遇到的警告本质是:Swift的String作为值类型,内部存储结构不稳定,直接通过inout变量生成UnsafeRawPointer时,会暴露它的内部存储而非安全的内容引用,不符合Objective-C关联对象对key的内存稳定性要求。
解决方案
关联对象的key必须是全局唯一且内存地址稳定的,以下两种方法可彻底消除警告:
方法1:改用NSString生成稳定的UnsafeRawPointer
将原有的Swift String key替换为NSString的内存地址,NSString是Objective-C引用类型,内存地址固定:
// 生成稳定的关联对象key private let tapGestureKey = UnsafeRawPointer(Unmanaged.passUnretained("tapGestureKey" as NSString).toOpaque()) extension UIView { var tapAction: (() -> Void)? { get { return objc_getAssociatedObject(self, tapGestureKey) as? (() -> Void) } set { objc_setAssociatedObject(self, tapGestureKey, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC) // 清理旧手势 gestureRecognizers?.filter { $0 is UITapGestureRecognizer }.forEach(removeGestureRecognizer) // 添加新手势(如果有回调) guard let action = newValue else { return } let tap = UITapGestureRecognizer(target: self, action: #selector(handleTap)) addGestureRecognizer(tap) isUserInteractionEnabled = true } } @objc private func handleTap() { tapAction?() } }
方法2:用字符串hash值生成唯一key
如果不想依赖NSString,也可以用字符串的hash值生成UnsafeRawPointer,同样能保证key的唯一性和稳定性:
private let tapGestureKey = UnsafeRawPointer(bitPattern: "tapGestureKey".hashValue)! // 后续的extension代码同方法1
关键说明
- 关联对象的key不能用Swift值类型(如String、Int)的inout引用,因为值类型的内存地址会随拷贝、赋值操作变化,导致关联对象失效或触发警告。
- 上述两种方法生成的key都是全局唯一且内存稳定的,完全符合Objective-C运行时的要求。
内容的提问来源于stack exchange,提问作者Christine
相关产品推荐
相关产品推荐

