ios - 用户位置更新后触发的函数

标签 ios swift callback location closures

重要说明:我知道我可以简单地在 didUpdateLocations 中调用我的 callback 函数并实现我想要的。不幸的是,由于在该项目中做出了一些预先存在的设计决策(我对此没有影响),因此无法采用这条路线。

我需要编写一个函数,在用户坐标第一次更新时触发,然后将这些坐标传递给完成处理程序。在我的例子中,该完成处理程序是一个名为 fetchCountry(fromLocation: CLLocation) 的函数,它返回与给定的 CLLocation 对应的国家/地区。

换句话说,我想编写一个类似于 didUpdateLocations 的函数,能够在收到这些更新后调用完成处理程序:

func getUserLocation(callback: @escaping (CLLocation?) -> Void) {

    // wait until user's location has been retrieved by location manager, somehow

    // prepare output for callback function and pass it as its argument
    let latitude = manager.location!.coordinate.latitude
    let longitude = manager.location!.coordinate.longitude
    let location = CLLocation(latitude: latitude, longitude: longitude)

    callback(location)
}

简而言之,getUserLocation 只是 didUpdateLocations 的包装器,但我真的不确定我将如何编写此函数以使其实现我想要的。

我更大的目标是在用户启动应用程序时仅当他们在特定国家/地区(例如美国)时向他们显示本地通知。我的应用程序很难决定在 AppDelegate.swift 中安排/不安排此通知,但在检索到用户位置之前无法做出此决定。我计划像这样在 appDelegate 中使用 getUserLocation:

我希望我已经清楚地表达了我希望使用带有完成处理程序 的函数来实现这一点。这是我希望我的代码在 AppDelegate.swift 中执行的操作(即我的用例):

// inside didFinishLaunchingWithOptions
UNUserNotificationCenter.current().requestAuthorization(options: [.badge, .alert, .sound]) { (granted, error) in
    if granted {

            // this is the use case of the function I am trying to write                         
            LocationManager.shared.getLocation(completion: { location in

                // fetches the country from given location using reverse geo-coding
                LocationManager.shared.fetchCountry(from: location, completion: { country in

                    if country == "United States" {                  
                        let notification = LocalNotification()
                        notificationManager.schedule(notification: notification)
                    }
                })
            })
        }
    }

最佳答案

编辑了整个答案。您需要使用同步 api(OperationQueueDispatchQueue 等),因为您的 CLLocationManager 甚至在 getUserLocation 被调用。单独的回调无法解决这个问题,这就是我已经删除该选项的原因。对于这种情况,我使用了 DispatchQueue,因为我更喜欢使用它,而不是各自使用它。

class LocationManager: NSObject, CLLocationManagerDelegate{

    static let shared: LocationManager()
    private let privateQueue = DispatchQueue.init("somePrivateQueue")
    private var latestLocation: CLLocation!{
        didSet{
            privateQueue.resume()
        }
    }

    func getUserLocation(queue: DispatchQueue, callback: @escaping (CLLocation?) -> Void) {
        if latestLocation == nil{
            privateQueue.suspend() //pause queue. wait until got a location
        }

        privateQueue.async{ //enqueue work. should run when latestLocation != nil

            queue.async{ //use a defined queue. most likely mainQueue

              callback(self.latestLocation)
              //optionally clear self.latestLocation to ensure next call to this method will wait for new user location. But if you are okay with a cached userLocation, then no need to clear.
            }
        }

    }

    func fetchCountry(from currentLocation: CLLocation, completion: ) //you already have this right?

    @objc func locationManager(_ manager: CLLocationManager, 
           didUpdateLocations locations: [CLLocation]){
         latestLocation = locations.last! //API states that it is guaranteed to always have a value
    }

}


如果可能,我也同意使用第三方库。这些代码将保证经过单元测试并处理边缘情况。然而,我上面的代码可能有一个错误(顺便说一句,我不知道)

关于ios - 用户位置更新后触发的函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56204190/

相关文章:

iphone - iOS 模拟器上的谷歌地图?

ios - 用于识别 iPhone 6 和 iPhone 6 plus 竖屏的尺寸等级

swift - 如何在 swift 中正确初始化游戏的全局变量

javascript - 将简单函数直接传递给 es6 Promise.then

javascript - 理解 jquery 回调

php - iOS 推送通知问题 它工作了一段时间,但有时不工作

iphone - 如何创建自动启动 iTunes 的 App Store 链接?

swift - 通过 viewDidAppear() 或 viewWillLayoutSubviews() 设置圆角半径?

swift - 无法从 SLComposeViewController 显示 UIAlert

javascript - 如何将现有的回调 API 转换为 Promise?