Làm thế nào để truy xuất tên thành phố hiện tại của người dùng?


Câu trả lời:


107

Những gì bạn phải làm là thiết lập một CLLocationManagertọa độ sẽ tìm thấy tọa độ hiện tại của bạn. Với tọa độ hiện tại, bạn cần sử dụng MKReverseGeoCoderđể tìm vị trí của mình.

- (void)viewDidLoad 
{  
    // this creates the CCLocationManager that will find your current location
    CLLocationManager *locationManager = [[[CLLocationManager alloc] init] autorelease];
    locationManager.delegate = self;
    locationManager.desiredAccuracy = kCLLocationAccuracyNearestTenMeters;
    [locationManager startUpdatingLocation];
}

// this delegate is called when the app successfully finds your current location
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation 
{
    // this creates a MKReverseGeocoder to find a placemark using the found coordinates
    MKReverseGeocoder *geoCoder = [[MKReverseGeocoder alloc] initWithCoordinate:newLocation.coordinate];
    geoCoder.delegate = self;
    [geoCoder start];
}

// this delegate method is called if an error occurs in locating your current location
- (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error 
{
 NSLog(@"locationManager:%@ didFailWithError:%@", manager, error);
}

// this delegate is called when the reverseGeocoder finds a placemark
- (void)reverseGeocoder:(MKReverseGeocoder *)geocoder didFindPlacemark:(MKPlacemark *)placemark
{
    MKPlacemark * myPlacemark = placemark;
    // with the placemark you can now retrieve the city name
    NSString *city = [myPlacemark.addressDictionary objectForKey:(NSString*) kABPersonAddressCityKey];
}

// this delegate is called when the reversegeocoder fails to find a placemark
- (void)reverseGeocoder:(MKReverseGeocoder *)geocoder didFailWithError:(NSError *)error
{
    NSLog(@"reverseGeocoder:%@ didFailWithError:%@", geocoder, error);
}

9
Một lưu ý: Bạn phải lưu trữ trình quản lý vị trí trong ivar (và có thể dừng nó lại sau khi bạn nhận được vị trí), nếu không nó sẽ được tự động đăng ký ngay lập tức và bạn sẽ không nhận được bất kỳ lệnh gọi lại nào được ủy quyền. Ngoài ra, bộ mã hóa địa lý ngược yêu cầu kết nối internet để hoạt động.
uliwitness

Bạn có thể cho tôi biết cách in Thành phố hoặc Vị trí Hiện tại trong Tiêu đề và Phụ đề trên Ghim không ???
Raju

1
@Frade #import <AddressBook / AddressBook.h>
Jonathan

18
MKReverseGeoCoder không được dùng nữa kể từ ios 5.0
adhg

Frade, tôi muốn bạn có thể nói những gì bạn phát hiện ra ... tiếng thở dài
David

122

Kể từ khi iOS 5 không MKReverseGeoCoderđược chấp nhận!

Vì vậy, bạn muốn sử dụng CLGeocodervớiCLLocationManager , rất đơn giản và hoạt động với khối.

Thí dụ:

- (void)locationManager:(CLLocationManager *)manager
    didUpdateToLocation:(CLLocation *)newLocation
           fromLocation:(CLLocation *)oldLocation
{
   [self.locationManager stopUpdatingLocation];

   CLGeocoder * geoCoder = [[CLGeocoder alloc] init];
    [geoCoder reverseGeocodeLocation:newLocation
                   completionHandler:^(NSArray *placemarks, NSError *error) {
                       for (CLPlacemark *placemark in placemarks) {
                           .... = [placemark locality];
                       }
                   }];
}

Chỉnh sửa: Thay vì một for invòng lặp, bạn cũng có thể làm:

NSString *locString = placemarks.count ? [placemarks.firstObject locality] : @"Not Found";

28

Điều này đang hoạt động tốt đối với tôi:

CLGeocoder *geocoder = [[CLGeocoder alloc] init] ;
[geocoder reverseGeocodeLocation:self.locationManager.location
               completionHandler:^(NSArray *placemarks, NSError *error) {
                   NSLog(@"reverseGeocodeLocation:completionHandler: Completion Handler called!");

                   if (error){
                       NSLog(@"Geocode failed with error: %@", error);
                       return;

                   }


                   CLPlacemark *placemark = [placemarks objectAtIndex:0];

                   NSLog(@"placemark.ISOcountryCode %@",placemark.ISOcountryCode);
                   NSLog(@"placemark.country %@",placemark.country);
                   NSLog(@"placemark.postalCode %@",placemark.postalCode);
                   NSLog(@"placemark.administrativeArea %@",placemark.administrativeArea);
                   NSLog(@"placemark.locality %@",placemark.locality);
                   NSLog(@"placemark.subLocality %@",placemark.subLocality);
                   NSLog(@"placemark.subThoroughfare %@",placemark.subThoroughfare);

               }];

Tại sao nó trả về một mảng? lạ lùng. Dẫu sao cũng xin cảm ơn.
Adam Waite

Đây là khối tình yêu bóng bẩy. Tôi đã đặt một điều kiện cho mảng dấu vị trí để đảm bảo rằng objectatindex: 0 thực sự tồn tại.
capikaw

4
Xin chào, tôi nhận được một lỗi, kCLErrorDomain error 8bạn có biết tại sao không?
maxisme

CLGeoCoder không được khai báo những gì tôi phải làm để nó có thể hoạt động những gì cần nhập và những gì cần thêm
Nhà phát triển iOS

16

Nếu ai đó đang cố gắng chuyển sang CLGeocoder từ MKReverseGeocoder thì tôi đã viết một bài đăng trên blog có thể hữu ích http://jonathanfield.me/jons-blog/clgeocoder-example.html

Về cơ bản, một ví dụ sẽ là, sau khi bạn đã tạo các đối tượng locationManager và CLGeocoder, chỉ cần thêm mã này vào viewDidLoad () của bạn và sau đó tạo một số nhãn hoặc vùng văn bản để hiển thị dữ liệu.

  [super viewDidLoad];
    locationManager.delegate = self;
    [locationManager startUpdatingLocation];

    locationManager.desiredAccuracy = kCLLocationAccuracyBestForNavigation;
    [self.CLGeocoder reverseGeocodeLocation: locationManager.location completionHandler: 
     ^(NSArray *placemarks, NSError *error) {


         CLPlacemark *placemark = [placemarks objectAtIndex:0];


             isoCountryCode.text = placemark.ISOcountryCode;
             country.text = placemark.country;
             postalCode.text= placemark.postalCode;
             adminArea.text=placemark.administrativeArea;
             subAdminArea.text=placemark.subAdministrativeArea;
             locality.text=placemark.locality;
             subLocality.text=placemark.subLocality;
             thoroughfare.text=placemark.thoroughfare;
             subThoroughfare.text=placemark.subThoroughfare;
             //region.text=placemark.region;



     }];

@macayer Có, sẽ sụp đổ nếu trống, nhưng sẽ không bao giờ trống nếu tôi hiểu đúng. Sẽ chứa 1 hoặc nhiều phần tử hoặc được nilvà các thông báo được gửi đến nilkết quả nil, cũng như quyền truy cập thuộc tính thông qua ký hiệu dấu chấm qua nil. Điều đó đang được nói, người ta nên luôn kiểm tra xem errorcó phải là không nil.
Victor Zamanian

3

Nếu ai đó cần nó trong Swift 3 , thì đây là cách tôi đã làm:

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

    let location = locations.first!
    let coordinateRegion = MKCoordinateRegionMakeWithDistance(location.coordinate, 500, 500)

    self.location = location
    self.locationManager?.stopUpdatingLocation()

    // Drop a pin at user's Current Location
    let myAnnotation: MKPointAnnotation = CustomPointAnnotation()
    myAnnotation.coordinate = CLLocationCoordinate2DMake(location.coordinate.latitude, location.coordinate.longitude)
    myAnnotation.title = "Localização"
    self.mapViewMK.addAnnotation(myAnnotation)

    self.mapViewMK.setRegion(coordinateRegion, animated: true)
    self.locationManager?.stopUpdatingLocation()
    self.locationManager = nil

    // Get user's current location name
    let geocoder = CLGeocoder()
    geocoder.reverseGeocodeLocation(self.location!) { (placemarksArray, error) in

        if (placemarksArray?.count)! > 0 {

            let placemark = placemarksArray?.first
            let number = placemark!.subThoroughfare
            let bairro = placemark!.subLocality
            let street = placemark!.thoroughfare

            self.addressLabel.text = "\(street!), \(number!) - \(bairro!)"
        }
    }
}

3

Sau khi thiết lập CLLocationManager, bạn sẽ nhận được cập nhật vị trí dưới dạng cặp vĩ độ / kinh độ. Sau đó, bạn có thể sử dụng CLGeocoder để chuyển đổi tọa độ thành tên địa điểm thân thiện với người dùng.

Đây là mã mẫu trong Swift 4 .

func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
    if let lastLocation = locations.last {
        let geocoder = CLGeocoder()

        geocoder.reverseGeocodeLocation(lastLocation) { [weak self] (placemarks, error) in
            if error == nil {
                if let firstLocation = placemarks?[0],
                    let cityName = firstLocation.locality { // get the city name
                    self?.locationManager.stopUpdatingLocation()
                }
            }
        }
    }
}

2

Bạn phải lấy vị trí hiện tại của người dùng và sau đó sử dụng MKReverseGeocoder để nhận ra thành phố.

Có một ví dụ tuyệt vời trong Hướng dẫn lập trình ứng dụng iPhone , chương 8. Khi bạn đã có vị trí khởi tạo bộ mã địa lý, hãy đặt đại biểu và đọc quốc gia từ dấu vị trí. Đọc tài liệu về MKReverseGeocodeDelegate và tạo các phương thức:

  • reverseGeocoder: didFindPlacemark:
  • reverseGeocoder: didFailWithError:

    MKReverseGeocoder *geocoder = [[MKReverseGeocoder alloc] initWithCoordinate:newLocation.coordinate];
    geocoder.delegate = self;
    [geocoder start];

1

Bạn có thể sử dụng mã này để nhận Thành phố Hiện tại: -

tiện ích mở rộng YourController: CLLocationManagerDelegate {func locationManager (manager: CLLocationManager, didUpdateLocations location: [CLLocation]) {

    CLGeocoder().reverseGeocodeLocation(manager.location!, completionHandler: {(placemarks, error)->Void in

        if (error != nil)
        {
            manager.stopUpdatingLocation()
            return
        }
        else
        {
            if placemarks!.count > 0
            {
                let placeMarksArrray: NSArray = placemarks!
                let pm = placeMarksArrray[0] as! CLPlacemark
                self.displayLocationInfo(pm)
                manager.stopUpdatingLocation()
            } else
            {
                print("Problem with the data received from geocoder")
            }
        }
    })
}

func displayLocationInfo(placemark: CLPlacemark!) {
    if (placemark != nil) {
        //stop updating location to save battery life
        locationLocation.stopUpdatingLocation()
        var tempString : String = ""
        if(placemark.locality != nil){
            tempString = tempString +  placemark.locality! + " "
            print(placemark.locality)
        }
        if(placemark.postalCode != nil){
            tempString = tempString +  placemark.postalCode! + " "
            print(placemark.postalCode)
        }
        if(placemark.administrativeArea != nil){
            tempString = tempString +  placemark.administrativeArea! + " "
            print(placemark.administrativeArea)
        }
        if(placemark.country != nil){
            tempString = tempString +  placemark.country! + " "



        }
        let dictForaddress = placemark.addressDictionary as! NSDictionary


        if let city = dictForaddress["City"] {
            print(city)



        }
        strLocation = tempString
    }
}

0
// place the function code below in desire location in program.

// [self getCurrentLocation];



-(void)getCurrentLocation
{
    CLGeocoder *geocoder = [[CLGeocoder alloc] init] ;
    [geocoder reverseGeocodeLocation:self->locationManager.location
                   completionHandler:^(NSArray *placemarks, NSError *error) {
                       NSLog(@"reverseGeocodeLocation:completionHandler: Completion Handler called!");

                       if (error){
                           NSLog(@"Geocode failed with error: %@", error);
                           return;

                       }


                       CLPlacemark *placemark = [placemarks objectAtIndex:0];

                       NSLog(@"placemark.ISOcountryCode %@",placemark.ISOcountryCode);
                       NSLog(@"placemark.country %@",placemark.country);
                        NSLog(@"placemark.locality %@",placemark.locality );
                       NSLog(@"placemark.postalCode %@",placemark.postalCode);
                       NSLog(@"placemark.administrativeArea %@",placemark.administrativeArea);
                       NSLog(@"placemark.locality %@",placemark.locality);
                       NSLog(@"placemark.subLocality %@",placemark.subLocality);
                       NSLog(@"placemark.subThoroughfare %@",placemark.subThoroughfare);

                   }];
}

0

Đây là lớp Swift nhỏ của tôi giúp tôi lấy thông tin được mã hóa địa lý ngược về vị trí hiện tại. Đừng quên về NSLocationWhenInUseUsageDescriptionlĩnh vực trong Info.plist.

class CurrentPlacemarkUpdater: NSObject, CLLocationManagerDelegate {

    private let locationManager = CLLocationManager()
    private let geocoder = CLGeocoder()

    private(set) var latestPlacemark: CLPlacemark?
    var onLatestPlacemarkUpdate: (() -> ())?
    var shouldStopOnUpdate: Bool = true

    func start() {
        locationManager.requestWhenInUseAuthorization()
        locationManager.desiredAccuracy = kCLLocationAccuracyKilometer
        locationManager.delegate = self
        locationManager.startUpdatingLocation()
    }

    func stop() {
        locationManager.stopUpdatingLocation()
    }

    fileprivate func updatePlacemark(for location: CLLocation) {
        geocoder.reverseGeocodeLocation(location) { [weak self] placemarks, error in
            if let placemark = placemarks?.first {
                self?.latestPlacemark = placemark
                self?.onLatestPlacemarkUpdate?()
                if self?.shouldStopOnUpdate ?? false {
                    self?.stop()
                }
            }
        }
    }

    func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
        if let location = locations.last {
            updatePlacemark(for: location)
        }
    }

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

}

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.