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

Swift开发:如何将MapKit获取的用户坐标存入另一视图控制器的数据库?

解决方案:传递MapKit坐标并存储到数据库

刚好做过类似的需求,给你几个实用的方案,根据你的视图控制器跳转逻辑选最合适的就行:

方案1:闭包(Closure)传递(轻量推荐)

这种方式适合两个视图控制器直接交互,耦合度低,代码简洁:

步骤1:修改MapKit所在的ViewController,添加闭包属性

class MapViewController: UIViewController, CLLocationManagerDelegate {
    let locationManager = CLLocationManager()
    // 定义闭包,用于传递坐标
    var onCoordinateReceived: ((CLLocationCoordinate2D) -> Void)?

    override func viewDidLoad() {
        super.viewDidLoad()
        locationManager.delegate = self
        locationManager.requestWhenInUseAuthorization()
        locationManager.startUpdatingLocation()
    }

    func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
        if let location = locations.first {
            let coordinate = location.coordinate
            print(coordinate)
            // 调用闭包把坐标传出去
            onCoordinateReceived?(coordinate)
            // 拿到坐标后建议停止更新,节省电量
            locationManager.stopUpdatingLocation()
        }
    }
}

步骤2:在数据库ViewController中接收坐标并存储

假设你是通过导航控制器跳转到MapVC,那么在跳转时设置闭包:

// 数据库ViewController中的跳转代码
let mapVC = MapViewController()
mapVC.onCoordinateReceived = { [weak self] coordinate in
    // 这里成功拿到坐标,调用存储方法
    self?.saveCoordinateToDB(coordinate: coordinate)
}
navigationController?.pushViewController(mapVC, animated: true)

然后实现存储方法(对应你提供的数据库代码):

func saveCoordinateToDB(coordinate: CLLocationCoordinate2D) {
    let building = buildingField.text?.trimmingCharacters(in: .whitespacesAndNewlines)
    guard let building = building, !building.isEmpty else {
        print("Building is Empty")
        return
    }

    // 将坐标转为字符串(SQLite常用文本存储,也可以用数值类型)
    let latitudeStr = String(coordinate.latitude)
    let longitudeStr = String(coordinate.longitude)

    // 绑定building(你的原代码)
    if sqlite3_bind_text(stmt, 5, building, -1, nil) != SQLITE_OK {
        print("Error binding building")
    }
    // 绑定纬度和经度(假设你的数据库表中这两个字段是第6、7位索引,根据实际调整)
    if sqlite3_bind_text(stmt, 6, latitudeStr, -1, nil) != SQLITE_OK {
        print("Error binding latitude")
    }
    if sqlite3_bind_text(stmt, 7, longitudeStr, -1, nil) != SQLITE_OK {
        print("Error binding longitude")
    }

    // 执行插入操作并处理结果
    if sqlite3_step(stmt) != SQLITE_DONE {
        print("Error inserting data into database")
    }
    sqlite3_reset(stmt)
}

方案2:通知中心(NotificationCenter)传递

适合跨多个页面、不想直接耦合的场景:

步骤1:MapVC中发送通知

func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
    if let location = locations.first {
        let coordinate = location.coordinate
        print(coordinate)
        // 发送通知,携带坐标数据
        NotificationCenter.default.post(
            name: NSNotification.Name(rawValue: "CoordinateReceivedNotification"),
            object: nil,
            userInfo: ["coordinate": coordinate]
        )
        locationManager.stopUpdatingLocation()
    }
}

步骤2:数据库VC中接收通知

class DatabaseViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()
        // 注册通知观察者
        NotificationCenter.default.addObserver(
            self,
            selector: #selector(handleCoordinateReceived(_:)),
            name: NSNotification.Name(rawValue: "CoordinateReceivedNotification"),
            object: nil
        )
    }

    @objc private func handleCoordinateReceived(_ notification: Notification) {
        // 解析坐标数据
        guard let coordinate = notification.userInfo?["coordinate"] as? CLLocationCoordinate2D else {
            print("Invalid coordinate data received")
            return
        }
        // 存储到数据库
        saveCoordinateToDB(coordinate: coordinate)
    }

    // 记得在页面销毁时移除观察者,避免内存泄漏
    deinit {
        NotificationCenter.default.removeObserver(self)
    }

    // 存储方法和方案1一致
    func saveCoordinateToDB(coordinate: CLLocationCoordinate2D) {
        // ... 同方案1的存储代码
    }
}

方案3:代理(Delegate)模式传递

适合需要更规范组件交互的场景,代码结构更清晰:

步骤1:定义代理协议

// 建议放在MapVC文件顶部或者单独的协议文件中
protocol CoordinateDelegate: AnyObject {
    func didReceiveCoordinate(_ coordinate: CLLocationCoordinate2D)
}

步骤2:MapVC中添加代理属性

class MapViewController: UIViewController, CLLocationManagerDelegate {
    let locationManager = CLLocationManager()
    // 代理属性,用weak避免循环引用
    weak var delegate: CoordinateDelegate?

    override func viewDidLoad() {
        super.viewDidLoad()
        locationManager.delegate = self
        locationManager.requestWhenInUseAuthorization()
        locationManager.startUpdatingLocation()
    }

    func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
        if let location = locations.first {
            let coordinate = location.coordinate
            print(coordinate)
            // 通知代理拿到坐标
            delegate?.didReceiveCoordinate(coordinate)
            locationManager.stopUpdatingLocation()
        }
    }
}

步骤3:数据库VC遵守代理协议

class DatabaseViewController: UIViewController, CoordinateDelegate {
    override func viewDidLoad() {
        super.viewDidLoad()
    }

    // 跳转时设置代理
    func goToMapVC() {
        let mapVC = MapViewController()
        mapVC.delegate = self
        navigationController?.pushViewController(mapVC, animated: true)
    }

    // 实现代理方法
    func didReceiveCoordinate(_ coordinate: CLLocationCoordinate2D) {
        saveCoordinateToDB(coordinate: coordinate)
    }

    // 存储方法和方案1一致
    func saveCoordinateToDB(coordinate: CLLocationCoordinate2D) {
        // ... 同方案1的存储代码
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.27 07:12:56