web-dev-qa-db-ja.com

iOSでデバイスの場所(国のみ)を取得する

IOSデバイスの国の場所を取得する必要があります。

CoreLocationをMKReverseGeocoderで使用しようとしています。ただし、これは非常に頻繁にエラーを返すようです。そして、私は国だけを必要とし、通りなどは必要ありません。

これをより安定した方法で行うにはどうすればよいですか?

58
johan

NSLocaleは、現在使用されている地域設定に関する設定であり、実際に居住している国を意味するものではありません。

CLLocationManagerを使用して現在の場所を取得し、CLGeocoderを使用して逆ジオコーディングを実行します。そこから国名を取得できます。

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

あなたのような識別子を取得します「US」(米国)、「ES」(スペイン)など.


In Swift

let countryCode = NSLocale.current.regionCode

Swift 2.2

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

CLLocationManagerに基づくソリューションと比較すると、このアプローチには長所と短所があります。主な短所は、ユーザーがデバイスを別の方法で構成した場合に、これがデバイスの物理的な場所であることを保証しないことです。しかし、これは代わりにユーザーがどの国に精神的/文化的に調整されているかを示すため、プロと見なすこともできます。休暇で海外に行くと、ロケールはまだ私の母国に設定されています。ただし、かなり大きな利点は、このAPIがCLLocationManagerのようにユーザー権限を必要としないことです。そのため、ユーザーの場所を使用する権限をまだ取得しておらず、ユーザーの顔にポップアップダイアログをスローすることを正当化できない場合(または、既にポップアップを拒否し、フォールバックが必要な場合)、これはおそらくAPIです使用したい。これのいくつかの典型的なユースケースは、パーソナライゼーション(文化的に関連するコンテンツ、デフォルトのフォーマットなど)と分析です。

94

@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]);
    }];
}
15
Matt

以下は、@ Denisと@Mattの回答をまとめてSwiftソリューションにしたものです。

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

Info.plistにもNSLocationAlwaysUsageDescriptionまたはNSLocationWhenInUseUsageDescriptionを設定することを忘れないでください!

11
lindanordstrom

これは、おそらく過度に遠回りの代替方法です。他のソリューションは、手動設定(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辞書で検索します。

辞書のiOSバージョンをpytzまたは他のソースで利用できるようにすると、タイムゾーン設定(多くの場合最新)に基づいて、サーバーの助けを借りずにすぐに国コードを検索できます。

NSLocaleを誤解しているかもしれません。地域のフォーマット設定またはタイムゾーン設定を通じて国コードを提供しますか?後者の場合、これは同じ結果を得るためのより複雑な方法です...

7
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
5

Swift 3の場合、さらに簡単です:

let countryCode = Locale.current.regionCode
3
Shaked Sayag

NSTimeZoneはCLLocationから取得できます: https://github.com/Alterplay/APTimeZones そしてローカルで動作します。

1
slatvick

@ロブ

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

これらのコードを使用して、地域の国コードを取得し、まだ取得していない場合は、電話設定->一般->言語と地域に移動して、希望する地域を設定します

0
Harikesh

電話デバイスのみに興味がある場合は、ここで説明した手法が役立つ場合があります。 iPhoneユーザーの国を決定する

0
ThomasW

国コードの完全なリストを返すSwift 3のクイックループを次に示します。

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

地域セットごとに国名を取得するための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)

prints:Optional( "NG")Optional( "ナイジェリア")。 //ナイジェリア地域セット用

0
Van