MapKit传递数据后二级地图视图卡顿问题求助
MapKit二级地图视图卡顿无法交互问题
问题现象
在SwiftUI项目中使用MapKit展示地图,点击按钮传递数据后,通过fullScreenCover弹出的二级地图视图(LeadLocationMapView)出现卡顿,无法正常执行缩放、拖拽等交互操作。测试发现,将视图模型的声明改为@StateObject后,地图可恢复正常交互。
相关代码实现
父视图代码
struct ParentView: View{ @StateObject var staffVM: StaffViewModel = StaffViewModel() var body: some View{ VStack{ ForEach(staffLeadsDataInfo) { item in StaffLead(name: "\(item.firstName ?? "") \(item.lastName ?? "")", phoneNumber: "\(staffVM.maskPhoneNumber(item.phoneNumber ?? ""))", referralId: "\(item.referralID ?? "")", date:"\(staffVM.convertDateFormat(item.createdAt ?? "Unknown"))", color:staffVM.colors.randomElement() ?? Color.cyan) .onTapGesture { staffVM.setUpForLeadDetails(serverId: item.product?.id ?? "", profilePicture: item.agent?.picture ?? "", firstName: item.agent?.firstName ?? "", lastName: item.agent?.lastName ?? "", leadCoordinates: item.location?.coordinates ?? [-1.286389, 36.817223], locations: item.location ?? LocationLead(type: "", coordinates: [0, 0], street1: "", street2: "", state: "", city: ""), notes:item.visitInformation?.notes ?? "", phoneNumber: item.phoneNumber ?? "", date:item.createdAt ?? "", leadId: item.serverId ?? "") staffVM.navigateToFirstMap.toggle() } } } .navigationDestination(isPresented: $staffVM.navigateToFirstMap) { FirstMapView(staffVM: staffVM).navigationBarBackButtonHidden(true) } } }
第一个地图视图代码
struct FirstMapView: View{ @ObservedObject var staffVM: StaffViewModel var body: some View{ Map(coordinateRegion: staffVM.mapRegionBinding, annotationItems: staffVM.locations) { location in MapAnnotation(coordinate: CLLocationCoordinate2D(latitude: location.coordinates?[0] ?? 0, longitude: location.coordinates?[1] ?? 0)) { ZStack{ Circle() .fill(Color.red).opacity(0.05) .frame(width:100, height:100) Image("pincode") } } } .cornerRadius(5) .frame(height:200) .fullScreenCover(isPresented: $staffVM.navigateToBiggerMap) { LeadLocationMapView(staffVM: staffVM) } } }
ViewModel核心代码
class StaffViewModel: ObservableObject { @Published var mapRegion: MKCoordinateRegion? var mapRegionBinding: Binding<MKCoordinateRegion> { Binding<MKCoordinateRegion>( get: { guard let region = self.mapRegion else { return MKCoordinateRegion() } return region }, set: { newRegion in self.mapRegion = newRegion } ) } // 其他已发布属性... }
ViewModel数据设置方法
func setUpForLeadDetails(serverId: String, profilePicture: String, firstName: String, lastName: String, leadCoordinates:[Double], locations: LocationLead, notes: String, phoneNumber: String, date: String, leadId: String) { self.serverId = serverId self.profilePicture = profilePicture self.phoneNumber = phoneNumber self.firstName = firstName self.lastName = lastName self.navigateToLeadDetails = true self.leadCoordinates = leadCoordinates let latitude = leadCoordinates.first ?? 0.0 let longitude = leadCoordinates.last ?? 0.0 let center = CLLocationCoordinate2D(latitude: latitude, longitude: longitude) let span = MKCoordinateSpan(latitudeDelta: 0.01, longitudeDelta: 0.01) self.mapRegion = MKCoordinateRegion(center: center, span: span) self.locationCenter = center self.locations.append(locations) self.notes = notes self.stringDate = date self.leadId = leadId print("Activated \(self.navigateToLeadDetails)") print("Coordinates are: \(self.leadCoordinates)") }
全屏地图视图代码
struct LeadLocationMapView: View { @ObservedObject var staffVM: StaffViewModel var body: some View { VStack{ Map(coordinateRegion: staffVM.mapRegionBinding) }.ignoresSafeArea() } }
问题原因分析
- ViewModel生命周期管理问题:子视图中使用
@ObservedObject接收ViewModel时,若ViewModel的生命周期未被根视图用@StateObject正确持有,可能导致视图频繁重绘。 - 可选类型Binding的性能损耗:
mapRegion为可选类型,自定义Binding的get方法在mapRegion为nil时会返回新的MKCoordinateRegion()实例(值类型),SwiftUI会判定值发生变化,触发Map组件频繁更新,最终导致卡顿。
解决方案
方案1:优化ViewModel的Binding实现
将mapRegion从可选类型改为带默认值的非可选类型,移除自定义Binding,直接使用SwiftUI自动生成的Binding:
class StaffViewModel: ObservableObject { // 初始化时设置默认区域,避免可选类型 @Published var mapRegion: MKCoordinateRegion = MKCoordinateRegion( center: CLLocationCoordinate2D(latitude: -1.286389, longitude: 36.817223), span: MKCoordinateSpan(latitudeDelta: 0.01, longitudeDelta: 0.01) ) // 移除自定义的mapRegionBinding,直接使用$mapRegion }
然后在视图中替换绑定:
// FirstMapView中 Map(coordinateRegion: $staffVM.mapRegion, annotationItems: staffVM.locations) { ... } // LeadLocationMapView中 Map(coordinateRegion: $staffVM.mapRegion)
方案2:确保ViewModel的正确生命周期持有
在根视图(ParentView)中必须用@StateObject初始化ViewModel,子视图(FirstMapView、LeadLocationMapView)用@ObservedObject接收,避免ViewModel被重复创建或意外销毁。
验证结果
采用上述方案后,二级地图视图的交互流畅度恢复正常,缩放、拖拽操作无卡顿。
内容的提问来源于stack exchange,提问作者Luka Šalipur
相关产品推荐
相关产品推荐

