在iOS中获取设备位置(仅限国家/地区)

时间:2011-12-16 12:58:41

标签: ios core-location

我需要获取iOS设备的国家/地区位置。

我一直在尝试将CoreLocation与MKReverseGeocoder一起使用。然而,这似乎经常发生错误。我只需要这个国家,不需要街道等。

如何以更稳定的方式完成?

14 个答案:

答案 0 :(得分:90)

NSString *countryCode = [[NSLocale currentLocale] objectForKey: NSLocaleCountryCode];

会为您提供一个标识符,例如“美国”(美国),“ES”(西班牙)等。


Swift 3

let countryCode = NSLocale.current.regionCode

Swift 2.2

let countryCode = NSLocale.currentLocale().objectForKey(NSLocaleCountryCode) as String

与基于CLLocationManager的解决方案相比,这种方法有利有弊。主要的缺点是,如果用户以不同方式配置设备,则无法保证这是设备的物理位置。然而,这也可以被视为专业人士,因为它反而显示用户在精神/文化上与哪个国家保持一致 - 因此,例如,我出国度假,然后现场仍然是我的祖国。然而,一个非常大的专业人士是这个API不需要像CLLocationManager那样的用户权限。因此,如果你还没有获得使用用户位置的权限,并且你无法证明在用户面前抛出弹出对话框(或者他们已经拒绝了弹出窗口而你需要回退),那么这可能是你的API想用。一些典型的用例可能是个性化(例如文化相关内容,默认格式等)和分析。

答案 1 :(得分:38)

NSLocale只是关于当前使用的区域设置的设置,并不代表您所在的实际国家/地区。

使用CLLocationManager获取当前位置& CLGeocoder执行反向地理编码。你可以从那里获得国家名称。

答案 2 :(得分:15)

@Denis的答案很好 - 这里有一些代码将他的答案付诸实践。这适用于您已设置为符合CLLocationManagerDelegate协议的自定义类。它有点简化(例如,如果位置经理返回多个位置,它只是第一个位置),但应该给人们一个不错的开始......

- (id) init //designated initializer
{
    if (self)
    {
        self.locationManager = [[CLLocationManager alloc] init];
        self.geocoder = [[CLGeocoder alloc] init];
        self.locationManager.delegate = self;
        [self.locationManager startMonitoringSignificantLocationChanges];
    }
    return self;
}

- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations
{
    if (locations == nil)
        return;

    self.currentLocation = [locations objectAtIndex:0];
    [self.geocoder reverseGeocodeLocation:self.currentLocation completionHandler:^(NSArray *placemarks, NSError *error)
    {
        if (placemarks == nil)
            return;

        self.currentLocPlacemark = [placemarks objectAtIndex:0];
        NSLog(@"Current country: %@", [self.currentLocPlacemark country]);
        NSLog(@"Current country code: %@", [self.currentLocPlacemark ISOcountryCode]);
    }];
}

答案 3 :(得分:11)

这是@Denis和@Matt的答案,为 Swift 3 解决方案汇总:

import UIKit
import CoreLocation

class ViewController: UIViewController, CLLocationManagerDelegate {

    let locationManager = CLLocationManager()
    let geoCoder = CLGeocoder()

    override func viewDidLoad() {
        super.viewDidLoad()

        locationManager.requestAlwaysAuthorization()
        if CLLocationManager.locationServicesEnabled() {
            locationManager.delegate = self
            locationManager.startMonitoringSignificantLocationChanges()
        }
    }

    func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
        guard let currentLocation = locations.first else { return }

        geoCoder.reverseGeocodeLocation(currentLocation) { (placemarks, error) in
            guard let currentLocPlacemark = placemarks?.first else { return }
            print(currentLocPlacemark.country ?? "No country found")
            print(currentLocPlacemark.isoCountryCode ?? "No country code found")
        }
    }
}

不要忘记在NSLocationAlwaysUsageDescription中设置NSLocationWhenInUseUsageDescriptionInfo.plist

答案 4 :(得分:7)

这是另一种可能过于迂回的方法。其他解决方案基于手动设置(NSLocale)或请求允许使用可拒绝的位置服务(CLLocationManager),因此它们有缺点。

您可以根据当地时区获取当前国家/地区。我的应用程序与安装了pytz的运行Python的服务器连接,该模块为时区字符串提供了国家代码字典。我只需要让服务器知道这个国家,所以我不必完全在iOS上进行设置。在Python方面:

>>> import pytz
>>> for country, timezones in pytz.country_timezones.items():
...     print country, timezones
... 
BD ['Asia/Dhaka']
BE ['Europe/Brussels']
BF ['Africa/Ouagadougou']
BG ['Europe/Sofia']
BA ['Europe/Sarajevo']
BB ['America/Barbados']
WF ['Pacific/Wallis']
...

在iOS方面:

NSTimeZone *tz = [NSTimeZone localTimeZone];
DLog(@"Local timezone: %@", tz.name); // prints "America/Los_Angeles"

我的服务器以本地时区名称发送,并在pytz country_timezones字典中查找。

如果您在pytz或其他来源中提供字典的iOS版本,则可以使用它在没有服务器帮助的情况下立即查找国家/地区代码,具体取决于时区设置(通常是最新的)。

我可能会误解NSLocale。它是否通过区域格式设置首选项或时区设置为您提供国家/地区代码?如果是后者,那么这只是获得相同结果的一种更复杂的方式......

答案 5 :(得分:5)

NSLocale *countryLocale = [NSLocale currentLocale];  
NSString *countryCode = [countryLocale objectForKey:NSLocaleCountryCode];
NSString *country = [countryLocale displayNameForKey:NSLocaleCountryCode value:countryCode];
NSLog(@"Country Locale:%@  Code:%@ Name:%@", countryLocale, countryCode, country);
//Country Locale:<__NSCFLocale: 0x7fd4b343ed40>  Code:US   Name:United States

答案 6 :(得分:4)

如@Denis Locale所述,它只是有关当前使用的区域设置的设置,并不意味着您所在的实际国家/地区。

但是,建议使用CLLocationManager获取当前位置并建议使用CLGeocoder执行反向地理编码,这意味着提示用户访问位置服务。

如何从移动运营商处获取国家/地区代码?

import CoreTelephony

guard carrier = CTTelephonyNetworkInfo().subscriberCellularProvider else {
    //iPad
    return
}

let countryST = carrier.isoCountryCode!

答案 7 :(得分:3)

对于Swift 3来说,它更简单:

let countryCode = Locale.current.regionCode

答案 8 :(得分:1)

您可以从CLLocation获取NSTimeZone:https://github.com/Alterplay/APTimeZones并在本地工作。

答案 9 :(得分:0)

如果您只对电话设备感兴趣,那么此处提到的技术可能对您有用:Determine iPhone user's country

答案 10 :(得分:0)

这是Swift 3中的快速循环,它返回完整的国家/地区代码列表。

let countryCode = NSLocale.isoCountryCodes
    for country in countryCode {
        print(country)
    }

答案 11 :(得分:0)

@Rob

let locale = Locale.current
let code = (locale as NSLocale).object(forKey: NSLocale.Key.countryCode) as! String?

使用这些代码,您将获得您所在地区的国家/地区代码,如果您没有静止,请更改它,只需进入手机设置 - &gt; general-&gt;语言&amp;区域并设置您想要的区域

答案 12 :(得分:0)

用于获取按地区设置的国家/地区名称的Swift 4.0代码:

    let countryLocale = NSLocale.current
    let countryCode = countryLocale.regionCode
    let country = (countryLocale as NSLocale).displayName(forKey: NSLocale.Key.countryCode, value: countryCode)
    print(countryCode, country)

打印:Optional(“ NG”)Optional(“ Nigeria”)。 //用于尼日利亚地区设置

答案 13 :(得分:-1)

    if let countryCode = Locale.current.regionCode {
        let country =   Locale.current.localizedString(forRegionCode: countryCode)
    }