You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

iOS 16 Core Data日记应用地图视图更新问题(设备正常模拟器异常)

问题:iOS日记应用中使用FindLocationView后地图未即时更新(仅模拟器问题)

我正在开发一款基于Core Data存储日记条目的iOS简易应用,目标系统为iOS 16,采用NavigationSplitView作为核心布局。每个日记条目支持可选位置,数据模型存储纬度、经度以及标记位置是否存在的布尔值,对应位置需展示地图。

调整代码结构,将位置与地图坐标区域的逻辑迁移到JournalEntryView后,出现了以下问题:用户点击「Find」按钮打开FindLocationView添加位置后,地图视图不会即时更新,仍显示旧位置;但切换到其他条目再返回后,地图就能正常显示新位置。原本预期onDismiss方法会触发地图更新,但并未生效。

后续验证发现,该问题仅在iOS模拟器中存在,真实设备上运行完全正常,目前问题已解决。


ContentView代码

struct ContentView: View {
    @Environment(\.managedObjectContext) private var viewContext

    @FetchRequest(
        sortDescriptors: [NSSortDescriptor(keyPath: \DailyEntry.timestamp, ascending: true)],
        animation: .default)
    private var items: FetchedResults<DailyEntry>
    @State private var searchPredicate = NSPredicate { _, _ in
        true
    }
    @State private var selectedItem: DailyEntry?
    @State private var columnVisibility = NavigationSplitViewVisibility.all
    @State private var searchString = ""

    var body: some View {
        NavigationSplitView(columnVisibility: $columnVisibility) {
            List {
                ForEach(items) { item in
                    Button {
                        selectedItem = item
                        columnVisibility = .automatic
                    } label: {
                        Text(item.timestamp, style: .date)
                    }
                }
                .onDelete(perform: deleteItems)
            }
            .searchable(text: $searchString)
            .toolbar {
                ToolbarItem(placement: .navigationBarTrailing) {
                    EditButton()
                }
                ToolbarItem {
                    Button(action: addItem) {
                        Label("Add Item", systemImage: "plus")
                    }
                }
            }
        } detail: {
            if let item = selectedItem {
                JournalEntryView(entry: item)
            }
            else {
                HStack {
                    Spacer()
                    Text("Select a journal entry or create a new one")
                }
                .padding()
            }
        }
        .onSubmit(of: .search) {
            searchPredicate = ...
            items.nsPredicate = searchPredicate
        }
        .onChange(of: searchString) { newValue in
            if newValue == "" {
                items.nsPredicate = nil
            }
        }
    }

    private func addItem() {
        ...
    }

    private func deleteItems(offsets: IndexSet) {
        ...
    }
}

JournalEntryView代码

struct JournalEntryView: View {
    @Environment(\.managedObjectContext) private var viewContext
    @ObservedObject var entry: DailyEntry
    @ObservedObject var locationManager = sharedLocationManager
    
    @State private var locationRequested = false
    @State private var locationPickerShowing = false
    @State private var mapRegion: MKCoordinateRegion = MKCoordinateRegion()
    @State private var mapLocation = CLLocationCoordinate2D()
    
    init(entry: DailyEntry) {
        self.entry = entry
        mapLocation = CLLocationCoordinate2D(latitude: entry.latitude, longitude: entry.longitude)
        mapRegion = MKCoordinateRegion(center: mapLocation, span: MKCoordinateSpan(latitudeDelta: 2.0, longitudeDelta: 2.0))
    }
    
    var body: some View {
        VStack(alignment: .leading) {
            HStack {
                DatePicker("Date:", selection: $entry.timestamp, displayedComponents: [.date])
                VStack {
                    if entry.hasLocation {
                        Map(coordinateRegion: $mapRegion, annotationItems: [IdentifiablePlace(location: mapLocation)]) { place in
                            MapMarker(coordinate: place.location)
                        }
                    }
                    HStack {
                        TextField("Location name", text: $entry.placeName)
                        Button("Find") {
                            locationPickerShowing = true
                        }
                        LocationButton(.currentLocation) {
                            locationManager.getLocation()
                            locationRequested = true
                        }
                    }
                }
            }
            ...
        }
        .padding()
        .onAppear() {
            setMap(latitude: entry.latitude, longitude: entry.longitude)
        }
        .onChange(of: locationManager.currentLocation) { newValue in
            if locationRequested {
                entry.latitude = locationManager.currentLocation.coordinate.latitude
                entry.longitude = locationManager.currentLocation.coordinate.longitude
                entry.hasLocation = true
                locationRequested = false
                setMap(latitude: entry.latitude, longitude: entry.longitude)
            }
        }
        .onChange(of: entry) { newValue in
            biblePassage = newValue.bibleSelection()
            if newValue.hasLocation {
                setMap(latitude: newValue.latitude, longitude: newValue.longitude)
            }
        }
        .sheet(isPresented: $locationPickerShowing, onDismiss: { setMap(latitude: entry.latitude, longitude: entry.longitude) }) {
            FindLocationView(entry: entry, isPresented: $locationPickerShowing, searchString: entry.placeName)
        }
    }
    
    func setMap(latitude: Double, longitude: Double) {
        if entry.hasLocation {
            let coordinate = CLLocationCoordinate2D(latitude: latitude, longitude: longitude)
            mapRegion = MKCoordinateRegion(center: coordinate, span: MKCoordinateSpan(latitudeDelta: 2.0, longitudeDelta: 2.0))
            mapLocation = coordinate
        }
    }
}

FindLocationView代码

struct FindLocationView: View {
    @Environment(\.managedObjectContext) private var viewContext
    @ObservedObject var entry: DailyEntry
    @Binding var isPresented: Bool
    @State var searchString: String
    
    @State private var location: CLLocationCoordinate2D?
    @State private var locationList: [CLPlacemark] = []
    @State private var placeMark: CLPlacemark?
    
    var body: some View {
        VStack(alignment: .leading) {
            Text("Enter a name:")
            HStack {
                TextField("Name", text: $searchString, prompt: Text("City, town, village"))
                    .onSubmit(of: .text) {
                        lookupLocation()
                    }
                Button("Search") {
                    lookupLocation()
                }
            }
            List(selection: $placeMark) {
                ForEach(locationList, id: \.self) { place in
                    let name = place.name ?? ""
                    let country = place.country ?? ""
                    let display = name == "" ? country : "\(name), \(country)"
                    Text(display)
                }
            }
            HStack {
                Spacer()
                Button("OK") {
                    if let newLocation = placeMark?.location {
                        entry.latitude = newLocation.coordinate.latitude
                        entry.longitude = newLocation.coordinate.longitude
                        entry.hasLocation = true
                        entry.placeName = placeMark?.name ?? searchString
                    }
                    isPresented = false
                }
            }
        }
        .padding()
        .onAppear() {
            if searchString != "" {
                lookupLocation()
            }
        }
    }
    
    func lookupLocation() {
        let geocoder = CLGeocoder()
        geocoder.geocodeAddressString(searchString) { placeMarks, error in
            if let placeMarks = placeMarks {
                locationList = placeMarks
            }
        }
    }
}

内容的提问来源于stack exchange,提问作者Mussau

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.27 09:17:05