Swift中使用泛型函数从UserDefaults加载时的调用报错咨询
解决方案
报错根源
这个问题和MyClass本身是否遵循Codable协议完全无关,核心是调用函数时的传参不符合参数的类型要求。
你定义的泛型函数中,type: T.Type这个参数需要接收具体类型对应的元类型实例:
- 对于
MyClass来说,合法的传入值是MyClass.self——这个值代表MyClass这个类型本身,它的类型正好是MyClass.Type,完全匹配T: Decodable的泛型约束。 - 你调用时传入的
MyClass.Type,是「MyClass的元类型的类型」,本身并不是可传入的元类型实例,自然会被Swift判定为没有遵循Decodable协议,触发类型不匹配的报错。
打个直观的比方:MyClass.self相当于你要递交给前台的具体文件(MyClass类型),它的封皮标注着“这是一份代表MyClass的元类型文件”;而MyClass.Type相当于“‘那份文件的类别描述’”,根本不是可递交的实体文件,自然会被前台拦下。
修正后的调用代码
// 原错误写法 if let object = loadFromUserDefaults(type: MyClass.Type, forKey: "key") { self.myProperty = object } else { MyClass() } // 正确写法 if let object = loadFromUserDefaults(type: MyClass.self, forKey: "key") { self.myProperty = object } else { // 注意原代码这里只初始化了MyClass实例但没有赋值,逻辑实际不会生效,需要补上赋值 self.myProperty = MyClass() }
额外提示:原else分支只写了
MyClass()没有把生成的实例赋值给self.myProperty,即使走到默认值分支,属性也不会被更新到默认值。
可选的函数优化
你当前的加载函数使用try?会直接吞掉所有解码阶段的错误,后续如果遇到存储数据格式变更、字段不匹配的问题,会直接返回nil很难排查原因,可以调整成带错误打印的版本,提升调试效率:
func loadFromUserDefaults<T: Decodable>(type: T.Type, forKey key: String) -> T? { // 直接用data(forKey:)替代object(forKey:) as? Data,写法更简洁 guard let data = UserDefaults.standard.data(forKey: key) else { return nil } do { let decoder = JSONDecoder() return try decoder.decode(T.self, from: data) } catch { // 输出解码错误详情,快速定位问题 print("UserDefaults 加载失败,Key: \(key), 错误: \(error)") return nil } }
内容的提问来源于stack exchange,提问作者appfrosch
相关产品推荐
相关产品推荐

