SwiftUI中App协议不兼容及Binding视图传参错误求助
问题总结
1. App协议兼容错误
为Market_ExampleApp添加带Binding参数的初始化方法后,触发错误:Type 'Market_ExampleApp' does not conform to protocol 'App'
2. MarketplaceShirtView类型转换错误
调用ShirtDetailView时出现两个类型不匹配问题:
- 无法将
$showDetailShirt(Binding<Bool>类型)转换为预期的Bool类型 - 无法将
Binding<Shirt>类型转换为预期的Shirt类型
相关代码片段
Market_ExampleApp代码
@main struct Market_ExampleApp: App { @StateObject var appModel: AppViewModel = .init() @StateObject var sharedData: SharedDataModel = SharedDataModel() @Binding var shirtData : Shirt @Binding var showDetailShirt: Bool @Binding var trouserData : Trouser @Binding var showDetailTrouser: Bool init(shirtData: Binding<Shirt>, showDetailShirt: Binding<Bool>, trouserData: Binding<Trouser>, showDetailTrouser: Binding<Bool>){ self._shirtData = shirtData self._showDetailShirt = showDetailShirt self._trouserData = trouserData self._showDetailTrouser = showDetailTrouser UITabBar.appearance().isHidden = true } @UIApplicationDelegateAdaptor(Appdelegate.self) var delegate var body: some Scene { WindowGroup { ContentView(shirtData: $shirtData, showDetailShirt: $showDetailShirt, trouserData: $trouserData, showDetailTrouser: $showDetailTrouser) .onOpenURL(perform: { url in Auth.auth().canHandle(url) }) } } }
ContentView代码
import SwiftUI struct ContentView: View { @AppStorage("log_status") var log_Status: Bool = false @StateObject var appModel: AppViewModel = .init() @StateObject var sharedData: SharedDataModel = SharedDataModel() @Binding var shirtData : Shirt @Binding var showDetailShirt: Bool @Binding var trouserData : Trouser @Binding var showDetailTrouser: Bool init(shirtData: Binding<Shirt>, showDetailShirt: Binding<Bool>, trouserData: Binding<Trouser>, showDetailTrouser: Binding<Bool>){ self._shirtData = shirtData self._showDetailShirt = showDetailShirt self._trouserData = trouserData self._showDetailTrouser = showDetailTrouser UITabBar.appearance().isHidden = true } var body: some View { Group{ if log_Status{ MainPage(shirtData: $shirtData, showDetailShirt: $showDetailShirt, trouserData: $trouserData, showDetailTrouser: $showDetailTrouser) } else{ OnBoardingPage() } } } }
MarketplaceShirtView代码
import SwiftUI struct MarketplaceShirtView: View { @EnvironmentObject var appModel: AppViewModel @StateObject var MarketplaceModel = MarketplaceViewModel() @State private var selectedMarketplaceFilter: MarketplaceFilterViewModel = .shirt @Namespace var animation : Namespace.ID @State var showDetailShirt = false @State var selectedShirt : Shirt! @EnvironmentObject var sharedData: SharedDataModel var body: some View { var columns = Array(repeating: GridItem(.flexible()), count: 2) ZStack{ VStack(spacing: 10){ HStack { Text("Find Shirts To Buy") } } } if MarketplaceModel.shirts.isEmpty{ ProgressView() } else{ ScrollView { LazyVGrid(columns: Array(repeating: GridItem(){ ForEach(MarketplaceModel.filteredShirt){shirt in ShirtView(shirtData: shirt) .onTapGesture { selectedShirt = shirt showDetailShirt.toggle() } } } }) } } if selectedShirt != nil && showDetailShirt{ ShirtDetailView(shirtData: Binding($selectedShirt)!, showDetailShirt: $showDetailShirt,animation: _animation) } } }
解决方案
修复App协议兼容问题
SwiftUI的App协议要求入口结构体必须提供无参数初始化方法,自定义带参数初始化会违反协议规则。正确做法是将共享状态放在顶层用@State声明,而非通过Binding传递给App结构体:
修改后的Market_ExampleApp代码:
@main struct Market_ExampleApp: App { @StateObject var appModel: AppViewModel = .init() @StateObject var sharedData: SharedDataModel = SharedDataModel() // 将状态改为顶层@State,而非Binding @State var shirtData: Shirt = Shirt() @State var showDetailShirt: Bool = false @State var trouserData: Trouser = Trouser() @State var showDetailTrouser: Bool = false // 恢复无参数初始化 init(){ UITabBar.appearance().isHidden = true } @UIApplicationDelegateAdaptor(Appdelegate.self) var delegate var body: some Scene { WindowGroup { ContentView(shirtData: $shirtData, showDetailShirt: $showDetailShirt, trouserData: $trouserData, showDetailTrouser: $showDetailTrouser) .onOpenURL(perform: { url in Auth.auth().canHandle(url) }) // 将全局对象注入环境,避免重复初始化 .environmentObject(appModel) .environmentObject(sharedData) } } }
同时修改ContentView,用@EnvironmentObject接收全局对象:
struct ContentView: View { @AppStorage("log_status") var log_Status: Bool = false // 通过环境接收全局对象,而非重新初始化 @EnvironmentObject var appModel: AppViewModel @EnvironmentObject var sharedData: SharedDataModel @Binding var shirtData : Shirt @Binding var showDetailShirt: Bool @Binding var trouserData : Trouser @Binding var showDetailTrouser: Bool init(shirtData: Binding<Shirt>, showDetailShirt: Binding<Bool>, trouserData: Binding<Trouser>, showDetailTrouser: Binding<Bool>){ self._shirtData = shirtData self._showDetailShirt = showDetailShirt self._trouserData = trouserData self._showDetailTrouser = showDetailTrouser UITabBar.appearance().isHidden = true } var body: some View { Group{ if log_Status{ MainPage(shirtData: $shirtData, showDetailShirt: $showDetailShirt, trouserData: $trouserData, showDetailTrouser: $showDetailTrouser) } else{ OnBoardingPage() } } } }
修复MarketplaceShirtView类型转换错误
问题源于ShirtDetailView的参数定义与传递类型不匹配,分两种情况处理:
情况1:ShirtDetailView需要值类型参数
如果ShirtDetailView的参数是Shirt和Bool,直接传递值即可:
// 替换原错误调用代码 if let selectedShirt = selectedShirt, showDetailShirt { ShirtDetailView(shirtData: selectedShirt, showDetailShirt: showDetailShirt, animation: animation) }
情况2:ShirtDetailView需要Binding类型参数
如果ShirtDetailView的参数是Binding<Shirt>和Binding<Bool>,直接用$符号传递绑定,同时修正animation的传递方式:
// 先确保ShirtDetailView的定义是Binding参数 struct ShirtDetailView: View { @Binding var shirtData: Shirt @Binding var showDetailShirt: Bool var animation: Namespace.ID var body: some View { // 视图内容 } } // 调用时的正确写法 if let selectedShirt = selectedShirt, showDetailShirt { ShirtDetailView(shirtData: $selectedShirt, showDetailShirt: $showDetailShirt, animation: animation) }
同时修正MarketplaceShirtView的语法错误(括号不匹配、强制解包风险):
struct MarketplaceShirtView: View { @EnvironmentObject var appModel: AppViewModel @StateObject var marketplaceModel = MarketplaceViewModel() @State private var selectedMarketplaceFilter: MarketplaceFilterViewModel = .shirt @Namespace var animation @State var showDetailShirt = false @State var selectedShirt: Shirt? // 改为可选类型,避免强制解包 @EnvironmentObject var sharedData: SharedDataModel var body: some View { let columns = Array(repeating: GridItem(.flexible()), count: 2) ZStack{ VStack(spacing: 10){ HStack { Text("Find Shirts To Buy") } } if marketplaceModel.shirts.isEmpty { ProgressView() } else { ScrollView { LazyVGrid(columns: columns) { ForEach(marketplaceModel.filteredShirt) { shirt in ShirtView(shirtData: shirt) .onTapGesture { selectedShirt = shirt showDetailShirt.toggle() } } } } } if let selectedShirt = selectedShirt, showDetailShirt { ShirtDetailView(shirtData: $selectedShirt, showDetailShirt: $showDetailShirt, animation: animation) } } } }
内容的提问来源于stack exchange,提问作者Mxyb
相关产品推荐
相关产品推荐

