使用 MapKit for SwiftUI 时出现性能问题

问题描述 投票:0回答:1

我正在使用一个 SwiftUI 视图,其中包含带有大量注释(范围从 30 到 100)的地图。除此之外,还有一个特定的注释,该注释会根据用户从列表中的选择而变化。列表选择可能会快速更改,可能每秒最多更改 10 次。

更新所选注释时,地图视图上的所有注释似乎都会重新加载。这会导致 CPU 使用率高和屏幕刷新率显着下降,尤其是在快速选择更改期间。

如何优化它,以便在更改 selectedAnnotation 时仅重新加载地图视图中选定的注释而不是所有注释?

以下是相关伪代码:

@State var annotations = [MKAnnotation]()
@State var selectedAnnotation: MKAnnotation?

Map {
    ForEach(annotations.indices, id: \.self) { idx in
        let anno = annotations[idx]
        Annotation("", coordinate: anno.coordinate) {
            Circle()
                .stroke(.black, lineWidth: 4)
                .fill(.white)
                .frame(width: 8, height: 8)
        }
    }
                
    if let selectedAnnotation {
         Annotation("", coordinate: selectedAnnotation.coordinate) {
             Circle()
                .stroke(.orange, lineWidth: 4)
                .fill(.white)
                .frame(width: 16, height: 16)
         }
    } else {
         EmptyMapContent()
    }
}

最小的可重现示例

import SwiftUI
import MapKit

struct Point: Identifiable {
    let id = UUID()
    var coordinate: CLLocationCoordinate2D
}

struct MapKitIssuesView: View {
    @State var points: [Point] = []
    @State var selectedCoord: CLLocationCoordinate2D?
    
    var body: some View {
        ZStack {
            Map {
                ForEach(points) { point in
                    let _ = print("reloaded \(point) at \(Date())")
                    Annotation("", coordinate: point.coordinate) {
                        Circle()
                            .fill(.black)
                            .frame(width: 4, height: 4)
                    }
                }
                            
                if let selectedCoord {
                     Annotation("", coordinate: selectedCoord) {
                         Circle()
                            .stroke(.orange, lineWidth: 4)
                            .fill(.white)
                            .frame(width: 16, height: 16)
                     }
                } else {
                     EmptyMapContent()
                }
            }
            .mapStyle(.standard(pointsOfInterest: .excludingAll))
            .onAppear {
                for lat in 30 ... 45 {
                    for lon in -137 ... -79 {
                        points.append(.init(coordinate: .init(latitude: Double(lat), longitude: Double(lon))))
                    }
                }
            }
            .onDisappear {
                points.removeAll()
            }
            
            VStack {
                Spacer()
                Button(action: {
                    selectedCoord = .init(latitude: .random(in: 30 ..< 45), longitude: .random(in: -137 ..< -79))
                }, label: {
                    Text("Change Selection")
                })
                .tint(.white)
            }
        }
        
    }
}

#Preview {
    MapKitIssuesView()
}
ios swift xcode swiftui mapkit
1个回答
0
投票

这是我的测试代码

import Foundation
import SwiftUI
import MapKit


struct ContentView: View {
    var body: some View {
        MapKitIssuesView()
    }
}

struct Point: Identifiable {
    let id = UUID()
    var coordinate: CLLocationCoordinate2D
}

struct MapKitIssuesView: View {
    @State var coordinates: [Point] = []
    @State var selectedCoord: CLLocationCoordinate2D?
    
    var body: some View {
        ZStack {
            Map {
                ForEach(coordinates) { p in
                    Annotation("", coordinate: p.coordinate) {
                        Circle()
                            .fill(.black)
                            .frame(width: 4, height: 4)
                    }
                }
                if let selectedCoord {
                    Annotation("", coordinate: selectedCoord) {
                        Circle()
                            .stroke(.orange, lineWidth: 4)
                            .fill(.orange)
                            .frame(width: 16, height: 16)
                    }
                }
            }
            .mapStyle(.standard(pointsOfInterest: .excludingAll))
            .onAppear {
                for lat in 30 ... 45 {
                    for lon in -137 ... -79 {
                        coordinates.append(
                            Point(coordinate: CLLocationCoordinate2D(latitude: Double(lat), longitude: Double(lon))))
                    }
                }
            }
            .onDisappear {
                //  coordinates.removeAll()
            }
            
            VStack {
                Spacer()
                Button("Change Selection") {
                    selectedCoord = .init(latitude: .random(in: 30 ..< 45),
                                          longitude: .random(in: -137 ..< -79))
                }
                .buttonStyle(.bordered)
                .tint(.red)
            }
        }
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.