我需要获取iOS设备的国家/地区位置。
我一直在尝试将CoreLocation与MKReverseGeocoder一起使用。然而,这似乎经常发生错误。我只需要这个国家,不需要街道等。
如何以更稳定的方式完成?
答案 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
中设置NSLocationWhenInUseUsageDescription
或Info.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)
}