【问题标题】:iOS CLLocationManager in a separate classiOS CLLocationManager 在一个单独的类中
【发布时间】:2012-07-15 19:53:49
【问题描述】:

我有多个需要获取用户位置的视图控制器,所以我想创建一个单独的类,视图控制器可以调用该类来获取用户的最新位置。

locationManager:didUpdateToLocation:fromLocation 返回 void。计算出用户的经纬度后,如何将经纬度数据传回 ViewController?

我可以尝试在我的 locationManaging 类中编写 getter 和 setter,但如果我这样做了,我怎么知道何时从我的 ViewController 类中调用 latitude getter 和 longitude getter 方法?如何让 ViewController 的主线程等待来自 locationManaging 类的纬度和经度值?

谢谢!

【问题讨论】:

  • locationManager:didUpdateToLocation:fromLocation 是一个委托方法。位置管理器使用此方法通知您的对象该位置已使用新值更新 - 由您来实现此方法以使用该值执行某些操作。

标签: ios xcode core-location cllocationmanager


【解决方案1】:

正如 user1071136 所说,单例位置管理器可能是您想要的。创建一个类,一个 NSObject 的子类,只有一个属性,CLLocationManager

LocationManagerSingleton.h:

#import <MapKit/MapKit.h>

@interface LocationManagerSingleton : NSObject <CLLocationManagerDelegate>

@property (nonatomic, strong) CLLocationManager* locationManager;

+ (LocationManagerSingleton*)sharedSingleton;

@end

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

要获取最近收到的位置,只需使用[LocationManagerSingleton sharedSingleton].locationManager.location。预热 GPS 可能需要几秒钟才能获得准确的位置。

【讨论】:

  • 可能想将您的@synchronized 块更新为dispatch_once
  • @Rickay 在飞行模式下会返回结果吗?
  • 如果你检查这个答案:(stackoverflow.com/questions/7376294/…)你会发现在这种情况下CLLocationManager返回最近获取的位置,而不是新的位置信息。
【解决方案2】:

创建一个具有latitudelongitude 属性、startLocatingendLocating 的单例类。在类中,创建一个CLLocationManager 实例,并将其委托设置为单例。在startLocatingendLocating 中,调用CLLocationManager 实例的相应方法。使委托方法更新latitudelongitude 属性。在其他ViewControllers 中,请阅读此单例的latitudelongitude 属性。

要知道何时从另一个 ViewController 读取这些属性,请在这些属性上设置观察者(请参阅 NSKeyValueObserving Protocol Reference

在执行此操作之前,请在 Internet 上查找现有代码。

完成此操作后,使用许可许可证将其上传到 GitHub。

【讨论】:

  • 谢谢!我的后续问题是.. 我怎么知道我的 ViewController 何时应该调用单例的纬度和经度属性?换句话说,我如何锁定我的 ViewController 的主线程以等待我的单例中的有效 lat long 值
  • 它在第二段(可能是在您阅读我最初的帖子时添加的)
  • 您访问观察者更改通知方法中的单例属性
  • 我今天试过了。但是我的代码在类被声明为单例之前没有更新位置。但为什么 ?为什么我们需要一个单例。我什至没有创建多个对象。我正在使用单个对象进行测试。
【解决方案3】:

根据上面的答案,这是我所做的,你可以在github上找到完整的例子https://github.com/irfanlone/CLLocationManager-Singleton-Swift

只需将此文件导入您的项目,然后您可以选择实施 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])
        }
    }

}

用法:

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)")
    }

}

【讨论】:

    【解决方案4】:

    这是我在 swift 中实现位置管理器单例时所做的。它基于user1071136的策略,以及this swift pattern

    //
    //  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()
    

    【讨论】:

    • 使用运行此代码的设备时戴上烤箱手套。
    • 我目前正在尝试使用您的课程,但该应用程序从不要求授权,我也没有获得位置。我需要做什么才能使用该课程?
    • 永远不要忘记 info.plst:stackoverflow.com/questions/24050633/…
    • @quellish 你能解释一下你的评论吗..你是说这是一个糟糕的解决方案 - 对于电池?我也在考虑一种为多个视图实现 CLLocation 的模式。
    • @SamYoungNY 此类正在设置位置精度和距离过滤器以拒绝任何精度低于 50 米的位置数据。像其他一些答案一样不断地打开/关闭位置更新对设备来说并不健康,也对应用程序没有帮助。
    【解决方案5】:

    在学习单例类获取用户位置的过程中,我下载了这段代码https://github.com/irfanlone/CLLocationManager-Singleton-Swift。在使用它在 Xcode8.3.3 Swift 3 上运行后,我无法在调试控制台中获得任何输出。事实上,我什至无法显示这个位置授权 dlalog。我怀疑来自单例的数据没有传递给视图控制器,但我无法解决这个问题,你能看出什么问题吗?谢谢。

    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)")
    }
    
    
    }
    

    【讨论】:

    • 您应该考虑自己提出问题,而不是发布您的问题作为答案。
    • 什么都不感谢。如果我开始一个类似标题的新问题。你会认为它是重复的!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-12-14
    • 1970-01-01
    • 2015-02-22
    • 1970-01-01
    相关资源
    最近更新 更多