SwiftUI新增第二个Environment Object时属性初始化报错如何解决
报错原因
- 核心问题是类名和属性名完全重名:你定义的
ObservableObject类命名为brandViewM,同时你在testApp中声明的@StateObject属性也命名为brandViewM。Swift编译器解析brandViewM()时,会优先匹配当前正在初始化的属性本身,而非同名类的构造函数,因此抛出两个报错:- 无法在属性初始化阶段调用实例成员
brandViewM,因此时self还未完成初始化 brandViewM不是可调用的函数类型,无法添加()执行
- 无法在属性初始化阶段调用实例成员
- 该问题和模型遵循
Equatable还是Hashable没有关联,完全是命名冲突导致的编译错误。
解决方案
遵循Swift标准命名规范修改命名,避免重名即可:类名采用大驼峰命名,实例属性采用小驼峰命名。
步骤1:修改ObservableObject类命名
struct BrandItem:Codable, Equatable { var selectedText:String var brandUsername:String var brandPassword:String } // 类名改为大驼峰 class BrandViewModel: ObservableObject { @Published var branditems: [BrandItem] = [] { didSet { saveBrandItem() } } let branditemsKey:String = "branditemsKey" init() { getBrandItems() } func getBrandItems() { guard let data = UserDefaults.standard.data(forKey: branditemsKey), let savedDotItems = try? JSONDecoder().decode([BrandItem].self, from: data) else { return } self.branditems = savedDotItems } func deleteBrandItem(indexSet:IndexSet){ branditems.remove(atOffsets: indexSet) } func addBrandItem(selectedText:String, brandUsername: String, brandPassword: String){ let newBrandItem = BrandItem(selectedText: selectedText, brandUsername: brandUsername, brandPassword: brandPassword) branditems.append(newBrandItem) print(newBrandItem) } func saveBrandItem() { if let encodedData = try? JSONEncoder().encode(branditems) { UserDefaults.standard.set(encodedData, forKey: branditemsKey) } } }
步骤2:修改入口处的属性声明与注入
@main struct testApp: App { @UIApplicationDelegateAdaptor(AppDelegate.self) var appDelegate @StateObject var listViewModel: ListViewModel = ListViewModel() // 类型用修改后的大驼峰类名,属性用小驼峰命名 @StateObject var brandViewModel: BrandViewModel = BrandViewModel() var body: some Scene { WindowGroup { NavigationView { ContentView() .onAppear(){ UITableView.appearance().backgroundColor = .clear } } .environmentObject(listViewModel) .environmentObject(brandViewModel) } } }
步骤3:同步修改视图中的环境对象声明
// 同步修改类型为修改后的大驼峰类名 @EnvironmentObject var brandVM: BrandViewModel
如果不想修改原类名,也可以临时通过添加模块名前缀解决冲突:@StateObject var brandViewM:brandViewM = 你的App模块名.brandViewM(),但该方案不符合命名规范,不推荐长期使用。
内容的提问来源于stack exchange,提问作者Lloyd English
相关产品推荐
相关产品推荐

