简体   繁体   English

iOS CLLocationManager在一个单独的类中

[英]iOS CLLocationManager in a separate class

I have multiple view controllers that need to get the user's location, so I wanted to create a separate class that the ViewControllers can call to get the user's latest location. 我有多个视图控制器需要获取用户的位置,所以我想创建一个单独的类,ViewControllers可以调用该类来获取用户的最新位置。

locationManager:didUpdateToLocation:fromLocation returns void. locationManager:didUpdateToLocation:fromLocation返回void。 How do I pass the latitude and longitude data back to my ViewControllers as soon as the user's latitude and longitude is calculated? 一旦计算出用户的纬度和经度,我如何将纬度和经度数据传回我的ViewControllers?

I could try writing getters and setters in my locationManaging class, but if I do that, how do I know when to call the latitude getter and longitude getter methods from my ViewController class? 我可以尝试在我的locationManaging类中编写getter和setter,但如果我这样做,我怎么知道何时从我的ViewController类中调用latitude getter和longitude getter方法? How do I hold the ViewController's main thread to wait for the latitude and longitude values from the locationManaging class? 如何保持ViewController的主线程等待来自locationManaging类的纬度和经度值?

Thanks! 谢谢!

As user1071136 said, a singleton location manager is probably what you want. 正如user1071136所说,单身人士的位置管理员可能就是你想要的。 Create a class, a subclass of NSObject, with just one property, a CLLocationManager . 使用一个属性CLLocationManager创建一个类,NSObject的子类。

LocationManagerSingleton.h: LocationManagerSingleton.h:

#import <MapKit/MapKit.h>

@interface LocationManagerSingleton : NSObject <CLLocationManagerDelegate>

@property (nonatomic, strong) CLLocationManager* locationManager;

+ (LocationManagerSingleton*)sharedSingleton;

@end

LocationManagerSingleton.m: LocationManagerSingleton.m:

#import "LocationManagerSingleton.h"

@implementation LocationManagerSingleton

@synthesize locationManager;

- (id)init {
    self = [super init];

    if(self) {
        self.locationManager = [CLLocationManager new];
        [self.locationManager setDelegate:self];
        [self.locationManager setDistanceFilter:kCLDistanceFilterNone];
        [self.locationManager setHeadingFilter:kCLHeadingFilterNone];
        [self.locationManager startUpdatingLocation];
        //do any more customization to your location manager
    }

    return self;
}    

+ (LocationManagerSingleton*)sharedSingleton {
    static LocationManagerSingleton* sharedSingleton;
    if(!sharedSingleton) {
        static dispatch_once_t onceToken;
        dispatch_once(&onceToken, ^{
            sharedSingleton = [LocationManagerSingleton new];
        }
    }

    return sharedSingleton;
}

- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation {
    //handle your location updates here
}

- (void)locationManager:(CLLocationManager *)manager didUpdateHeading:(CLHeading *)newHeading {
    //handle your heading updates here- I would suggest only handling the nth update, because they
    //come in fast and furious and it takes a lot of processing power to handle all of them
}

@end

To get the most recently received location, simply use [LocationManagerSingleton sharedSingleton].locationManager.location . 要获取最近收到的位置,只需使用[LocationManagerSingleton sharedSingleton].locationManager.location It might take a few seconds to warm up the GPS to get accurate locations. 可能需要几秒钟来预热GPS以获得准确的位置。

Create a singleton class which has a latitude and longitude properties, startLocating and endLocating . 创建一个具有latitudelongitude属性的单例类, startLocatingendLocating In the class, create a CLLocationManager instance, and set its delegate to be the singleton. 在类中,创建一个CLLocationManager实例,并将其委托设置为单例。 In startLocating and endLocating , call the appropriate methods of the CLLocationManager instance. startLocatingendLocating ,调用CLLocationManager实例的相应方法。 Make the delegate methods update the latitude and longitude properties. 使委托方法更新latitudelongitude属性。 In other ViewControllers , read this singleton's latitude and longitude properties. 在其他ViewControllers ,读取此单例的latitudelongitude属性。

To know when to read those properties from another ViewController , set an observer on these properties (see the NSKeyValueObserving Protocol Reference 要知道何时从另一个ViewController读取这些属性,请在这些属性上设置观察者(请参阅NSKeyValueObserving协议参考

Before doing this, look up the Internets for existing code. 在此之前,请查找Internets以获取现有代码。

After doing this, upload it to GitHub with a permissive license. 执行此操作后,使用许可许可证将其上载到GitHub。

Based on the above answers, here is what I did and you can find the complete example on github https://github.com/irfanlone/CLLocationManager-Singleton-Swift 根据上面的答案,这就是我所做的,你可以在github上找到完整的例子https://github.com/irfanlone/CLLocationManager-Singleton-Swift

Just import this file in your project, then you can either choose to implement the LocationUpdateProtocol or listen to notification for location updates 只需在项目中导入此文件,然后您可以选择实施LocationUpdateProtocol或收听位置更新通知

import MapKit

protocol LocationUpdateProtocol {
    func locationDidUpdateToLocation(location : CLLocation)
}

/// Notification on update of location. UserInfo contains CLLocation for key "location"
let kLocationDidChangeNotification = "LocationDidChangeNotification"

class UserLocationManager: NSObject, CLLocationManagerDelegate {

    static let SharedManager = UserLocationManager()

    private var locationManager = CLLocationManager()

    var currentLocation : CLLocation?

    var delegate : LocationUpdateProtocol!

    private override init () {
        super.init()
        self.locationManager.delegate = self
        self.locationManager.desiredAccuracy = kCLLocationAccuracyBest
        self.locationManager.distanceFilter = kCLLocationAccuracyHundredMeters
        locationManager.requestAlwaysAuthorization()
        self.locationManager.startUpdatingLocation()
    }

    // MARK: - CLLocationManagerDelegate

    func locationManager(manager: CLLocationManager, didUpdateToLocation newLocation: CLLocation, fromLocation oldLocation: CLLocation) {
        currentLocation = newLocation
        let userInfo : NSDictionary = ["location" : currentLocation!]

        dispatch_async(dispatch_get_main_queue()) { () -> Void in
            self.delegate.locationDidUpdateToLocation(self.currentLocation!)
            NSNotificationCenter.defaultCenter().postNotificationName(kLocationDidChangeNotification, object: self, userInfo: userInfo as [NSObject : AnyObject])
        }
    }

}

Usage: 用法:

class ViewController: UIViewController, LocationUpdateProtocol {

    var currentLocation : CLLocation!

    override func viewDidLoad() {
        super.viewDidLoad()

        NSNotificationCenter.defaultCenter().addObserver(self, selector: "locationUpdateNotification:", name: kLocationDidChangeNotification, object: nil)

        let LocationMgr = UserLocationManager.SharedManager
        LocationMgr.delegate = self

    }

    // MARK: - Notifications

    func locationUpdateNotification(notification: NSNotification) {
        let userinfo = notification.userInfo
        self.currentLocation = userinfo!["location"] as! CLLocation
        print("Latitude : \(self.currentLocation.coordinate.latitude)")
        print("Longitude : \(self.currentLocation.coordinate.longitude)")

    }

    // MARK: - LocationUpdateProtocol

    func locationDidUpdateToLocation(location: CLLocation) {
        currentLocation = location
        print("Latitude : \(self.currentLocation.coordinate.latitude)")
        print("Longitude : \(self.currentLocation.coordinate.longitude)")
    }

}

Here's what I did when implementing a location manger singleton in swift. 这是我在swift中实现位置管理器单例时所做的。 It's based on user1071136's strategy, as well as this swift pattern . 它基于user1071136的策略,以及这种快速模式

//
//  UserLocationManager.swift
//
//  Use: call SharedUserLocation.currentLocation2d from any class


import MapKit

class UserLocation: NSObject, CLLocationManagerDelegate {

    var locationManager = CLLocationManager()

    // You can access the lat and long by calling:
    // currentLocation2d.latitude, etc

    var currentLocation2d:CLLocationCoordinate2D?


    class var manager: UserLocation {
        return SharedUserLocation
    }

    init () {
        super.init()
        if self.locationManager.respondsToSelector(Selector("requestAlwaysAuthorization")) {
            self.locationManager.requestWhenInUseAuthorization()
        }
        self.locationManager.delegate = self
        self.locationManager.desiredAccuracy = kCLLocationAccuracyBest
        self.locationManager.distanceFilter = 50
        self.locationManager.startUpdatingLocation()
    }

    func locationManager(manager: CLLocationManager!, didUpdateLocations locations: [AnyObject]!) {
        self.currentLocation2d = manager.location.coordinate

    }
}

let SharedUserLocation = UserLocation()

In the process of learning to obtain user location in a singleton class, I downloaded this code https://github.com/irfanlone/CLLocationManager-Singleton-Swift . 在学习获取单例类中的用户位置的过程中,我下载了此代码https://github.com/irfanlone/CLLocationManager-Singleton-Swift After foddleing with it to make in run on Xcode8.3.3 Swift 3, I cannot get any output in the debug console. 在使用Xcode8.3.3 Swift 3进行运行后,我无法在调试控制台中获得任何输出。 In fact I can't even get this location autherization dlalog to display. 实际上我甚至无法显示此位置autherization dlalog。 I suspect the data from the singleton is not passed to the view controller, but I cannot fine the solution, can you see what is wrong? 我怀疑来自单例的数据没有传递给视图控制器,但是我不能解决问题,你能看出什么是错的吗? Thanks. 谢谢。

The corrected code for Swift 3 is: Swift 3的更正代码是:

//The singleton:
import MapKit

protocol LocationUpdateProtocol {
func locationDidUpdateToLocation(_ location : CLLocation)
}

let kLocationDidChangeNotification = "LocationDidChangeNotification"

class UserLocationManager: NSObject, CLLocationManagerDelegate {

static let SharedManager = UserLocationManager()

fileprivate var locationManager = CLLocationManager()

var currentLocation : CLLocation?

var delegate : LocationUpdateProtocol!

fileprivate override init () {
    super.init()
    self.locationManager.delegate = self
    self.locationManager.desiredAccuracy = kCLLocationAccuracyBest
    self.locationManager.distanceFilter = kCLLocationAccuracyHundredMeters
    locationManager.requestAlwaysAuthorization()
    self.locationManager.startUpdatingLocation()
}

// MARK: - CLLocationManagerDelegate
func locationManager(manager: CLLocationManager,didUpdateToLocation newLocation: CLLocation, fromLocation oldLocation: CLLocation) {
    currentLocation = newLocation
    let userInfo : NSDictionary = ["location" : currentLocation!]


    DispatchQueue.main.async() { () -> Void in
        self.delegate.locationDidUpdateToLocation(self.currentLocation!)
        NotificationCenter.default.post(name: Notification.Name(kLocationDidChangeNotification), object: self, userInfo: userInfo as [NSObject : AnyObject])
    }
}

}



  // The ViewController
    import UIKit
    import CoreLocation

 class ViewController: UIViewController, LocationUpdateProtocol {

var currentLocation : CLLocation!

override func viewDidLoad() {
    super.viewDidLoad()

    NotificationCenter.default.addObserver(self, selector: #selector(ViewController.locationUpdateNotification(_:)), name: NSNotification.Name(rawValue: kLocationDidChangeNotification), object: nil)

    let LocationMgr = UserLocationManager.SharedManager
    LocationMgr.delegate = self

}

// MARK: - Notifications

func locationUpdateNotification(_ notification: Notification) {
    let userinfo = notification.userInfo
    self.currentLocation = userinfo!["location"] as! CLLocation
    print("Latitude : \(self.currentLocation.coordinate.latitude)")
    print("Longitude : \(self.currentLocation.coordinate.longitude)")

}

// MARK: - LocationUpdateProtocol

func locationDidUpdateToLocation(_ location: CLLocation) {
    currentLocation = location
    print("Latitude : \(self.currentLocation.coordinate.latitude)")
    print("Longitude : \(self.currentLocation.coordinate.longitude)")
}


}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM