如何使用CLLocationManager-Swift获取当前经纬度

45

我想使用Swift获取一个位置的当前经纬度,并通过标签显示它们。我尝试过这样做,但标签上什么也没有显示。

import UIKit
import CoreLocation
class ViewController: UIViewController, CLLocationManagerDelegate{

    @IBOutlet weak var longitude: UILabel!
    @IBOutlet weak var latitude: UILabel!
    let locationManager = CLLocationManager()

    override func viewDidLoad() {
        super.viewDidLoad()
        if (CLLocationManager.locationServicesEnabled()) {
            locationManager.delegate = self
            locationManager.desiredAccuracy = kCLLocationAccuracyBest
            locationManager.requestWhenInUseAuthorization()
            locationManager.startUpdatingLocation()
        } else {
            println("Location services are not enabled");
        }
    }

    // MARK: - CoreLocation Delegate Methods

    func locationManager(manager: CLLocationManager!, didFailWithError error: NSError!) {
         locationManager.stopUpdatingLocation()
         removeLoadingView()
         if (error) != nil {
             print(error)
          }
     }

    func locationManager(manager: CLLocationManager!, didUpdateLocations locations: [AnyObject]!) {
        var locationArray = locations as NSArray
        var locationObj = locationArray.lastObject as CLLocation
        var coord = locationObj.coordinate
        longitude.text = coord.longitude
        latitude.text = coord.latitude
        longitude.text = "\(coord.longitude)"
        latitude.text = "\(coord.latitude)"
    }
}

1
可能是Swift中获取用户位置的CLLocation Manager的重复问题。 - Nate Cook
9个回答

86

依我的看法,当你寻找的解决方案非常简单时,你过于复杂化了你的代码。

我通过使用以下代码实现了它:

首先创建一个CLLocationManager实例并请求授权。

var locManager = CLLocationManager()
locManager.requestWhenInUseAuthorization()

然后检查用户是否允许授权。

var currentLocation: CLLocation!

if 
   CLLocationManager.authorizationStatus() == .authorizedWhenInUse ||
   CLLocationManager.authorizationStatus() ==  .authorizedAlways
{         
    currentLocation = locManager.location        
}

只需这样使用它

label1.text = "\(currentLocation.coordinate.longitude)"
label2.text = "\(currentLocation.coordinate.latitude)"
你关于将它们设置为label.text的想法是正确的,但我能想到的唯一原因是用户没有授权,这就是为什么你当前的位置数据将是nil的原因。
但是你需要调试并告诉我们。同时,CLLocationManagerDelegate不是必要的。
希望这有所帮助。如果你有疑问,请随时问。

1
你的第二个代码块应该放在哪里?在委托方法中吗? - Chris Harrison
1
通常我会把它放在“viewdidload”或“awakefromnib”中,但它可以在任何地方使用。只要请求用户允许使用他们的位置并且用户授权,它就没有限制。 - S.H.
3
我不同意这个建议。上面的代码甚至没有启动位置管理器——它只是确保位置管理器被授权。位置管理器当前的位置读数可能已经过时且极其不准确。当你激活位置管理器并请求位置更新时,前几个位置结果往往非常糟糕。你真的需要设置委托、开始位置更新,并检查所获取的位置更新的准确度读数,直到它们稳定下来。 - Duncan C
1
@DuncanC 话虽如此。尊重您的意见,但这段代码对我有效,我已经在为客户创建的应用程序中使用它了。 更直接地说,OP要求“使用Swift获取位置的当前经纬度”。因为显然它对他不起作用。这使它显然起作用,就像对我一样,从而回答了他的问题。如果您想谈论LocationManager准确性,那么我的朋友是另一个话题。 - S.H.
@MadisMaenni 我和你一样遇到了同样的问题。它还是卡住了,还是已经有新的解决方案了? - Marfin. F
显示剩余2条评论

36

对于 Swift 3:

首先,您需要在 info.plist 中设置允许接收用户的 GPS 定位信息。

enter image description here

NSLocationWhenInUseUsageDescription 设置为任意字符串。 并且 / 或者将 NSLocationAlwaysUsageDescription 设置为任意字符串。

然后:

import UIKit
import MapKit

class ViewController: UIViewController {

    var locManager = CLLocationManager()
    var currentLocation: CLLocation!

    override func viewDidLoad() {
        super.viewDidLoad()
        locManager.requestWhenInUseAuthorization()

        if (CLLocationManager.authorizationStatus() == CLAuthorizationStatus.authorizedWhenInUse ||
            CLLocationManager.authorizationStatus() == CLAuthorizationStatus.authorizedAlways){
            guard let currentLocation = locManager.location else {
                return
            }
            print(currentLocation.coordinate.latitude)
            print(currentLocation.coordinate.longitude)
        }
    }
}

完成。


1
这段代码在“print(currentLocation.coordinate.latitude)”行给我报错。 - Bijender Singh Shekhawat
@BijenderSinghShekhawat 好的,请告诉我是什么错误。怎么样? - David Seek
@MicroR,是的。 - David Seek
它使用相同的传感器。 - David Seek
@DavidSeek 对我来说,它总是进入警戒语句并返回。你能帮我解决一下吗? - Yogesh Patel
显示剩余4条评论

16

尽管还有其他建议,但你应该使用CLLocationManagerDelegate来安全地检索位置(如果不使用它,在位置管理器没有足够的时间更新时可能会得到空位置)。我强烈建议在静态共享帮助程序中包装位置管理器代码(类似以下内容):

class Locator: NSObject, CLLocationManagerDelegate {
    enum Result <T> {
      case .Success(T)
      case .Failure(ErrorType)
    }

    static let shared: Locator = Locator()

    typealias Callback = (Result <Locator>) -> Void

    var requests: Array <Callback> = Array <Callback>()

    var location: CLLocation? { return sharedLocationManager.location  }

    lazy var sharedLocationManager: CLLocationManager = {
        let newLocationmanager = CLLocationManager()
        newLocationmanager.delegate = self
        // ...
        return newLocationmanager
    }()

    // MARK: - Authorization

    class func authorize() { shared.authorize() }
    func authorize() { sharedLocationManager.requestWhenInUseAuthorization() }

    // MARK: - Helpers

    func locate(callback: Callback) {
        self.requests.append(callback)
        sharedLocationManager.startUpdatingLocation()
    }

    func reset() {
        self.requests = Array <Callback>()
        sharedLocationManager.stopUpdatingLocation()
    }

    // MARK: - Delegate

    func locationManager(manager: CLLocationManager, didFailWithError error: NSError) {
        for request in self.requests { request(.Failure(error)) }
        self.reset()
    }

    func locationManager(manager: CLLocationManager, didUpdateLocations locations: Array <CLLocation>) {
        for request in self.requests { request(.Success(self)) }
        self.reset()
    }

}

然后在视图加载(或任何需要获取当前位置的地方)中运行:

Locator.shared.locate { result in
  switch result {
  case .Success(locator):
    if let location = locator.location { /* ... */ }
  case .Failure(error):
    /* ... */
  }
}

我遇到了一个错误:“不允许在类型'Locator'中嵌套泛型类型'Result'”。我在Swift中从未见过这种错误。有什么修复建议吗? - Clay Ellis
@ClayEllis 把枚举类型 Result 的声明放到类外面,就可以正常工作了。 - yogs
按照指示使用时,出现错误:在UIViewController中使用未解决的标识符“locator”。 - Ankit Vyas
1
无法在Swift 4和Xcode 10中工作,请检查一次并编辑您的答案。 - nitin.agam
尝试在locator和error之前加上let。希望能有所帮助。Locator.shared.locate { (result) in switch result { case .success(let locator): break case .failure(let err): break
} }
- Usman

3

在Swift中

import UIKit
import CoreLocation

class ViewController: UIViewController, CLLocationManagerDelegate {

    //Labels outlets

    @IBOutlet var localityTxtField: UITextField!
    @IBOutlet var postalCodeTxtField: UITextField!
    @IBOutlet var aAreaTxtField: UITextField!
    @IBOutlet var countryTxtField: UITextField!

    let locationManager = CLLocationManager()

    //View Didload

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
    }

     //Button Location

    @IBAction func findMyLocation(_ sender: AnyObject) {
        locationManager.delegate = self
        locationManager.desiredAccuracy = kCLLocationAccuracyNearestTenMeters
        locationManager.requestWhenInUseAuthorization()
        locationManager.startUpdatingLocation()
    }

    func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
        CLGeocoder().reverseGeocodeLocation(manager.location!, completionHandler: {(placemarks, error)->Void in

            if (error != nil) {
                print("Reverse geocoder failed with error" + (error?.localizedDescription)!)
                return
            }

            if (placemarks?.count)! > 0 {

                print("placemarks",placemarks!)
                let pm = placemarks?[0]
                self.displayLocationInfo(pm)
            } else {
                print("Problem with the data received from geocoder")
            }
        })
    }

    func displayLocationInfo(_ placemark: CLPlacemark?) {
        if let containsPlacemark = placemark {

            print("your location is:-",containsPlacemark)
            //stop updating location to save battery life
            locationManager.stopUpdatingLocation()
            let locality = (containsPlacemark.locality != nil) ? containsPlacemark.locality : ""
            let postalCode = (containsPlacemark.postalCode != nil) ? containsPlacemark.postalCode : ""
            let administrativeArea = (containsPlacemark.administrativeArea != nil) ? containsPlacemark.administrativeArea : ""
            let country = (containsPlacemark.country != nil) ? containsPlacemark.country : ""

            localityTxtField.text = locality
            postalCodeTxtField.text = postalCode
            aAreaTxtField.text = administrativeArea
            countryTxtField.text = country
        }

    }


    func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) {
          print("Error while updating location " + error.localizedDescription)
    }
}

3

在当前线程中,提出了一种没有委托的解决方案,但在 Xcode 9.1 模拟器测试中它没有起作用,位置为 nil。以下代码有效:

 import UIKit
 import MapKit

class ViewController: UIViewController, CLLocationManagerDelegate {

var locationManager: CLLocationManager!

override func viewDidLoad() {
    super.viewDidLoad()

    if (CLLocationManager.locationServicesEnabled())
    {
        locationManager = CLLocationManager()
        locationManager.delegate = self
        locationManager.desiredAccuracy = kCLLocationAccuracyBest
        locationManager.requestAlwaysAuthorization()
        locationManager.startUpdatingLocation()
    }
}

func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation])
{

    let location = locations.last! as CLLocation

    /* you can use these values*/
    let lat = location.coordinate.latitude
    let long = location.coordinate.longitude
}

override func didReceiveMemoryWarning() {
    super.didReceiveMemoryWarning()
    // Dispose of any resources that can be recreated.
}


}

1

我是初学者,但我用以下方法解决了这个问题:

我创建了一个继承自CLLocationManagerDelegate的类的扩展,并按照以下步骤进行:

1.在您的ViewController中导入CoreLocation

import CoreLocation

2. 然后在您的 ViewController 中初始化位置管理器和位置变量。

var locManager = CLLocationManager()
var currentUserLocation: CLLocation!

在viewDidLoad()中请求位置初始化代理和requestUsageDescription: ``` locManager.requestWhenInUseAuthorization() locManager.delegate = self locManager.requestLocation() ```
然后我刚创建了一个扩展来继承CLLocationManagerDelegate的viewController: ``` extension theNameOfYourViewController: CLLocationManagerDelegate{
func locationManager(_ manager: CLLocationManager, didFailWithError error: Swift.Error) { print(error) }
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) { // .requestLocation will only pass one location to the locations array // hence we can access it by taking the first element of the array if let location = locations.first { print(location.coordinate.latitude) print(location.coordinate.longitude)
} } } ```

只需记得根据您的需要更改名称,每当您需要位置时,只需使用请求位置函数即可。

    locManager.requestLocation()

0

我同意上面Kevin的观点,但如果你在寻找更简单的少量代码,以下内容就足够了: 一定要使用CLLocationManagerDelegate

Swift 4:

在viewDidLoad中,您可以添加以下内容

 locationManager.requestWhenInUseAuthorization()


if (CLLocationManager.authorizationStatus() == CLAuthorizationStatus.authorizedWhenInUse) || (CLLocationManager.authorizationStatus() == CLAuthorizationStatus.authorizedAlways) {

            currentLocation = locationManager.location
            print(currentLocation.coordinate.latitude)
            print(currentLocation.coordinate.longitude)

        }

    }

当用户授权或拒绝权限时,对于第一个请求只需响应一次:

 func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {

            if status == .authorizedWhenInUse {

                locationManager.requestLocation()
                currentLocation = locationManager.location
                print(currentLocation.coordinate.latitude)
                print(currentLocation.coordinate.longitude)
                //Process location information and update.

    }

0
请确保将以下键添加到 Info.plist 文件中:
隐私 - 使用期间定位权限说明 隐私 - 始终使用定位权限说明
创建用户类:
import Foundation
import CoreLocation
import MapKit

class User: NSObject, ObservableObject {
    
    @Published var position =  CLLocationCoordinate2D(latitude: 0.0, longitude: 0.0)
    
    let manager = CLLocationManager()

    override init() {
        super.init()
        manager.delegate = self
        manager.requestWhenInUseAuthorization()
        manager.requestLocation()
    }
    
}

extension User: CLLocationManagerDelegate {
    
    func locationManagerDidChangeAuthorization(_ manager: CLLocationManager) {
        print("Location services authorization request")
    }
    
    func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
        print("User location updated")
        print("Updated position: \(locations.first?.coordinate.latitude ?? 00)")
        
        if let location = locations.first {
            self.position = location.coordinate
        }
    }
    
    func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) {
        print("Failed to find user's location: \(error.localizedDescription)")
    }

    
}

0

更新

Swift 5+
Xcode 13+

请在 info.plist 中添加这些权限。
<key>NSLocationWhenInUseUsageDescription</key>
    <string>This app needs your location to show nearby services</string>

    <key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
    <string>This app needs your location to show nearby services</string>

    <key>NSLocationAlwaysUsageDescription</key>
    <string>This app needs your location to show nearby services</string>

enter image description here

在你的视图控制器中导入这个

import CoreLocation

在viewDidLoad()方法中
override func viewDidLoad() {
        locationManager.requestWhenInUseAuthorization()
        locationManager.requestLocation()
}

创建类似这样的扩展

extension RegisterViewController : CLLocationManagerDelegate {

    func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) {
         print("error:: \(error.localizedDescription)")
    }

    func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {
        if status == .authorizedWhenInUse {
            locationManager.requestLocation()
        }
    }

    func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
        if let locationSafe = locations.last {
            locationManager.stopUpdatingLocation()
            let latitude = locationSafe.coordinate.latitude
            let longitude = locationSafe.coordinate.longitude
            self.currentLatitude = latitude
            self.currentLongitude = longitude
            print(" Lat \(latitude) ,  Longitude \(longitude)")
            
        }
        if locations.first != nil {
            print("location:: \(locations[0])")
        }

    }

}

运行并检查此内容

enter image description here


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接