为啥 CoreData 不保存任何东西?

Posted

技术标签:

【中文标题】为啥 CoreData 不保存任何东西?【英文标题】:Why isn't CoreData saving anything?为什么 CoreData 不保存任何东西? 【发布时间】:2021-12-25 02:39:30 【问题描述】:

在我的代码中,用户输入他们的地址,然后将其更改为位置坐标。然后它应该保存到核心数据,另一个视图控制器访问这些坐标并将它们固定在地图上。所以,我的代码可以正常工作,但是在我关闭应用程序并再次打开它之后,地图将位置固定在纬度 0 经度 0 处(基本上它会忘记保存的数据)。

查看控制器 1:

//
//  Preferences.swift
//  distanceTester
//
//  Created by Vaibhav Satishkumar on 12/19/21.
//

import UIKit
import CoreLocation
import CoreData

class Preferences: UIViewController, UITextFieldDelegate 


    

    var data = [User]()
    lazy var geocoder = CLGeocoder()
    

    
    @IBOutlet var countryTextField: UITextField!
    @IBOutlet var streetTextField: UITextField!
    @IBOutlet var cityTextField: UITextField!
    @IBOutlet var locationLabel: UILabel!
    
    override func viewDidLoad() 
        super.viewDidLoad()
        latCor.delegate = self
        longCor.delegate = self
        
       
        let user = User(context: context)
        
        appDelegate.saveContext()
        
       
    
    @IBOutlet weak var activityIndicatorView: UIActivityIndicatorView!
    @IBOutlet var geocodeButton: UIButton!
    
    @IBAction func geocode(_ sender: UIButton) 
        guard let country = countryTextField.text else  return 
        guard let street = streetTextField.text else  return 
        guard let city = cityTextField.text else  return 

        // Create Address String
        let address = "\(country), \(city), \(street)"

        // Geocode Address String
        geocoder.geocodeAddressString(address)  (placemarks, error) in
            // Process Response
            self.processResponse(withPlacemarks: placemarks, error: error)
        

        // Update View
        geocodeButton.isHidden = true
        activityIndicatorView.startAnimating()
    

    private func processResponse(withPlacemarks placemarks: [CLPlacemark]?, error: Error?) 
        // Update View
        geocodeButton.isHidden = false
        activityIndicatorView.stopAnimating()

        if let error = error 
            print("Unable to Forward Geocode Address (\(error))")
            locationLabel.text = "Unable to Find Location for Address"

         else 
            var location: CLLocation?

            if let placemarks = placemarks, placemarks.count > 0 
                location = placemarks.first?.location
            

            if let location = location 
                let coordinate = location.coordinate
                locationLabel.text = "\(coordinate.latitude), \(coordinate.longitude)"
                let user = User(context: context)
                user.lat = coordinate.latitude
                user.long = coordinate.longitude
                
                appDelegate.saveContext()

             else 
                locationLabel.text = "No Matching Location Found"
            
        
    
    @IBOutlet weak var latCor: UITextField!
    
    @IBOutlet weak var longCor: UITextField!
    
    @IBAction func saveCor(_ sender: Any) 
            saveData()
        fetchData()
    
    
    func saveData()
        let user = User(context: context)
        
        user.lat = latCor.text!.doubleValue
        user.long = longCor.text!.doubleValue
        do
            try context.save()
        
        catch 
              //error
        
        
        
        appDelegate.saveContext()   
    
    
    
    func fetchData()
        do 
            data = try context.fetch(User.fetchRequest())
            
            for each in data 
                print("Latitude:\(each.lat)/aLongitude: \(each.long)/n")
                
            
        
        catch
            //error
        
    


extension String 
    var doubleValue: Double 
        return Double(self) ?? 0
    


查看控制器 2:

import MapKit
import UIKit
import CoreLocation
import UserNotifications
import MessageUI
import GoogleMobileAds



class ViewController: UIViewController, CLLocationManagerDelegate, UNUserNotificationCenterDelegate, MFMessageComposeViewControllerDelegate, GADBannerViewDelegate 
    func messageComposeViewController(_ controller: MFMessageComposeViewController, didFinishWith result: MessageComposeResult) 
        
    
    
    
    
    
    var data = [User]()
    let user = User(context: context)
   
    @IBOutlet var mapView: MKMapView!// <<< add this and connect to the label in IB
    
    @IBOutlet weak var positionLabel: UILabel!
    
    let manager = CLLocationManager()
    
    override func viewDidLoad() 
        
        super.viewDidLoad()
        fetchData()
        
        mapView.layer.cornerRadius = 16
        
        
        
        
        manager.delegate = self
        manager.requestAlwaysAuthorization()
        manager.startUpdatingLocation()
        manager.allowsBackgroundLocationUpdates = true
        manager.pausesLocationUpdatesAutomatically = false
        manager.startUpdatingLocation()
        
        
        // Do any additional setup after loading the view.
        // Do any additional setup after loading the view.
    
    private func initializeLocationServices()
        manager.delegate = self
        
    
    
    
    
    
    
    
    
    override func viewDidAppear(_ animated: Bool) 
        
        super.viewDidAppear(animated)
        
        
    
    
    var coordinate1 = CLLocationCoordinate2D()
    
    func fetchData()
        do 
            data = try context.fetch(User.fetchRequest())
            for each in data 
                print("Latitude:\(each.lat)/aLongitude: \(each.long)/n")
                coordinate1.latitude = each.lat
                coordinate1.longitude = each.long
                appDelegate.saveContext()
                
            
        
        catch
            //urmom
        
    
    
    
    func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) 
        
        if let location = locations.first
            manager.startUpdatingLocation()
            print(location)
            render(location)
        
        func render(_ location: CLLocation)
            fetchData()
            appDelegate.saveContext()
            
            
            let span = MKCoordinateSpan (latitudeDelta: 0.01, longitudeDelta: 0.01)
            let region = MKCoordinateRegion(center: coordinate1, span: span)
            
            
            mapView.setRegion(region, animated: true)
            
            mapView.showsUserLocation = true
            
            let pin = MKPointAnnotation()
            pin.coordinate = coordinate1
            
            pin.title = "your home"
            pin.subtitle = "Location"
            
            if coordinate1.latitude != 0
                mapView.addAnnotation(pin)
            
            else
                coordinate1.latitude = user.lat
                coordinate1.longitude = user.long
            
            
            
            
            
            // 1
            
        
    



【问题讨论】:

Core Data 不是初学者技术。你确定你在这里做出了最好的架构决定吗? 是的,我有,请帮忙 每次您执行User(context: context) 时,都会在Core Data 中创建一个新的用户对象,因此您的核心数据存储中必须有很多空用户。您需要了解 Core Data 是什么以及如何正确使用它。 【参考方案1】:

问题一定出在你的保存方法上。您无需调用应用程序委托进行保存,而是需要在您的方法中创建上下文。

  let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
    let user = User(context: context)
    user.location = //whatever you want to save.
    do 
        try context.save()
    
    catch let error as NSError 
        print("Could not save. \(error)")
    

【讨论】:

以上是关于为啥 CoreData 不保存任何东西?的主要内容,如果未能解决你的问题,请参考以下文章

Core Data 的 Save 方法第一次调用“nil” - 为啥?

如何在 Core Data 中正确保存?

CoreData - 创建新实体 - 为啥不需要保存它?

在插入Core Data之前检查textfield是否为空

为啥调试器不知道我的 Core Data 生成的托管对象类上的方法? (附代码)

为啥保存托管对象上下文更改 isDeleted 值?