You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Xcode 9.3/Swift 4.1中无法创建仅限类的协议问题求助

解决Swift 4.1中弱引用存储协议类型的编译错误

这个问题是Swift 4.1(对应Xcode 9.3)的类型检查严格化导致的——虽然你的ThemeListener协议已经标记为继承AnyObject,但Swift现在要求明确区分协议类型和遵守该协议的类类型,而WeakRef<T>的约束T: AnyObject只接受类类型,不直接接受协议类型。

针对WeakRef的解决方法

你有两种简洁的修复方式:

方法1:调整类型别名,明确使用AnyObject & ThemeListener

修改你的类型别名,让它指向同时满足AnyObject和ThemeListener约束的类型,这样就能符合WeakRef的泛型要求:

class WeakRef<T> where T: AnyObject {
    private(set) weak var value: T?
    init(value: T?) {
        self.value = value
    }
}

protocol ThemeListener: AnyObject { }
// 修改类型别名,明确约束
typealias WeakRefThemeListener = WeakRef<AnyObject & ThemeListener>

这样你创建实例时,传入任何遵守ThemeListener的类对象(比如UIView/UIViewController子类)都能正常工作,而且保持了WeakRef的通用性。

方法2:让WeakRef直接约束到ThemeListener

如果你的WeakRef只用来存储ThemeListener订阅者,可以直接修改WeakRef的泛型约束,这样类型别名就不需要额外处理:

// 直接约束T为遵守ThemeListener的类
class WeakRef<T: ThemeListener> where T: AnyObject {
    private(set) weak var value: T?
    init(value: T?) {
        self.value = value
    }
}

protocol ThemeListener: AnyObject { }
typealias WeakRefThemeListener = WeakRef<ThemeListener>

针对NSHashTable的解决方法

NSHashTable的问题本质和WeakRef一致——它的泛型参数需要是AnyObject类型。你可以直接创建弱引用哈希表,存入对象时自动隐式转换,取出时再转回ThemeListener:

// 创建弱引用的哈希表
let listenerTable = NSHashTable<AnyObject>.weakObjects()

// 添加订阅者(比如一个UIViewController子类实例)
let viewController: SomeViewController = ...
listenerTable.add(viewController)

// 遍历订阅者时转换类型
for listener in listenerTable.allObjects.compactMap({ $0 as? ThemeListener }) {
    // 调用ThemeListener的方法
}

这样既保证了弱引用存储,又能正确处理协议类型的转换,避免内存泄漏。

内容的提问来源于stack exchange,提问作者Brett

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.29 06:39:37