ios개발/개념 정리

<스위프트> CLGeocoder(), CLLocation(), MapView

studying develop 2020. 3. 5. 20:10

참고 <https://greenchobo.tistory.com/8>

 

CLGeocoder()는 위도와 경도를 가져온다.

CLLocation()은 ios 맵 디비에서 주소를 가져온다 함. 

 

<https://sanghuiiiiii.tistory.com/entry/SWIFT-%ED%98%84%EC%9E%AC-%EC%9C%84%EC%B9%98-%EC%A3%BC%EC%86%8C-%EA%B0%80%EC%A0%B8%EC%98%A4%EA%B8%B0-%EB%AF%B8%EC%84%B8%EB%A8%BC%EC%A7%80%EC%95%B1-1-Day>

 

이게 풀 코드이다.

 

근데 위의 설명만으로는 이해하고 구현하기 어려워서 애플 문서를 좀 참고 했다.[https://developer.apple.com/documentation/corelocation/cllocationmanager

 


CLLocationManager 

Overview

You use instances of this class to configure, start, and stop the Core Location services. A location manager object supports the following location-related activities:

  • Tracking large or small changes in the user’s current location with a configurable degree of accuracy.

  • Reporting heading changes from the onboard compass.

  • Monitoring distinct regions of interest and generating location events when the user enters or leaves those regions.

  • Reporting the range to nearby beacons.

Assign a custom object to the delegate property, conforming to the CLLocationManagerDelegate protocol. Assign the delegate before starting any location services. The system calls the delegate's locationManager(_:didChangeAuthorization:) method immediately when the location manager is created. All location and heading-related updates and events are delivered to that delegate.

 

여기서 음 씨엘로케이션 메니저라는 것이 좀 중요해 보인다. 

 

See Adding Location Services to Your App for more information.

 

이 링크를 따라가 읽어보니 , 델리게이트에 locationManager() 메소드를 구현해서 앱이 로케이션 서비스를 지원할 수 없는 에러 상황 처리나, 권한이 변함에 대응하게 해주는 메소드라 한다. 음? ㅋㅋ

 

Handle Errors in the Delegate Methods

Implement the failure-related methods in the delegate to fail gracefully when location services are not available on a device. If you try to start an unavailable service, the CLLocationManager object calls one of the failure-related methods of its delegate. For example, if region monitoring is unavailable, the object calls the locationManager(_:monitoringDidFailFor:withError:) method. You may want to update the UI in your app when specific location services are not available.

 

Ask for Authorization and Handle Changes

Determine the authorization status your app needs. Ask for authorization to use location services when your users access location related functionality in your app. See Choosing the Location Services Authorization to Request for more information.

 

Implement your delegate’s locationManager(_:didChangeAuthorization:), which the system calls as soon as your app creates the location manager, and any time your app’s authorization status changes. Use this method to respond to changes in your app’s authorization status and perform the appropriate actions for each state. For example, you may want to turn on or off your app’s location features as appropriate when authorization changes.

 

그리고 이게 최종 사용법 같은데

Start Location Services and Receive Events

You must set the delegate object before you use other methods on your CLLocationManagerinstance. Next, you must:

  • Call the appropriate method in CLLocationManager to start the delivery of events.

  • Receive location and heading related updates in the associated delegate object.

  • Call the appropriate method in CLLocationManager to stop the service when your app no longer needs to receive the location events.

For the services you use, configure any properties associated with that service accurately. Core Location manages power aggressively by turning off hardware when it’s not needed. For example, setting the desired accuracy for location events to one kilometer gives the location manager the flexibility to turn off GPS hardware and rely solely on the WiFi or cell radios, which can lead to significant power savings.

 

요약하면 시작하려면 적절한 메소드를 부르고, 위치를 받고 방향을 업데이트 하고, 서비스 끝내려고 해도 적절한 메소드 호출하라는듯 ㅋㅋ

 


 

NSLocationWhenInUseUsageDescription

 

This app has attempted to access privacy-sensitive data without a usage description. The app's Info.plist must contain an “NSLocationWhenInUseUsageDescription” key with a string value explaining to the user how the app uses this data

 

이 키의 스트링값을 설정해야 한다.

위에 always랑 usage가 있는데, 저거 두개로는 부족한지 when in usage를 추가하라해서 추가했다.

 

 


 

그런데 지금 문제가 있다.

 

이 코드가 실행되도 0,0으로 떴다. (나중에 추가한건데, 이유가 객체에 생성한 변수를 갱신 안해줘서 그랬다. 코드에는 추가되어있다)

    public func settingLocationManager() {
        //self는 함수를 호출하는 자기 자신인가?? CLocation 클래스가 아니겠지?
        locationManager.delegate = self
        locationManager.requestWhenInUseAuthorization()
        locationManager.desiredAccuracy = kCLLocationAccuracyHundredMeters
        locationManager.startUpdatingLocation()
        
        //여기서 갱신해줘야되네
        self.currentLocation = (locationManager.location?.coordinate.latitude , locationManager.location?.coordinate.longitude) as! CLocation.CurrentLocation
        
        //alarmGetLocation의 델리게이트에서가 아니라 아니라 여기서 출력해야 제대로 출력하네?
        //print("in settingLocationManager: \(locationManager.location?.coordinate.longitude) , \(locationManager.location?.coordinate.latitude)")
    }

 

로그가 이렇게 뜨는데

in locationManager
current Location : 0.0 , 0.0
구름많음
in locationManager
current Location : 37.785834 , -122.406417
구름많음

 

내가 의심한 부분은 locationManager.startUpdatingLocation()이 호출되고 업데이트가 바로 안되는건가 싶었다. 

그런데 [https://developer.apple.com/documentation/corelocation/cllocationmanager/1423750-startupdatinglocation]

이 읽어보니 호출되면 바로 리턴되는데, 위치를 알려주도록 locationManager(_:didUpdateLocations:). 이 메소드가 호출된다 함.

위치 계산에 시간이 좀 걸리기도 하는듯? 몇초 걸린다고 써 있는듯 영어 능력 부족; 

 

This method returns immediately. Calling this method causes the location manager to obtain an initial location fix (which may take several seconds) and notify your delegate by calling its locationManager(_:didUpdateLocations:) method..

 

음 넘어갈라 했는데 이해해야 될거 같아서 복붙한다. 로케이션을 가져오는 방법에 대한 전반적인 흐름이다.!!!!

Discussion

This method returns immediately. Calling this method causes the location manager to obtain an initial location fix (which may take several seconds) and notify your delegate by calling its locationManager(_:didUpdateLocations:) method. After that, the receiver generates update events primarily when the value in the distanceFilter property is exceeded. Updates may be delivered in other situations though. For example, the receiver may send another notification if the hardware gathers a more accurate location reading.

 

Calling this method several times in succession does not automatically result in new events being generated. Calling stopUpdatingLocation() in between, however, does cause a new initial event to be sent the next time you call this method.

 

If you start this service and your app is suspended, the system stops the delivery of events until your app starts running again (either in the foreground or background). If your app is terminated, the delivery of new location events stops altogether. Therefore, if your app needs to receive location events while in the background, it must include the UIBackgroundModes key (with the location value) in its Info.plist file.

 

In addition to your delegate object implementing the locationManager(_:didUpdateLocations:) method, it should also implement the locationManager(_:didFailWithError:) method to respond to potential errors

 


MapView를 추가할 것이다.

MKMapView

맵킷맵뷰에 대한 애플 문서이다. [https://developer.apple.com/documentation/mapkit/mkmapview]

 

You use this class as-is to display map information and to manipulate the map contents from your application. You can center the map on a given coordinate, specify the size of the area you want to display, and annotate the map with custom information. When you initialize a map view, you specify the initial region for that map to display by setting the region property of the map. A region is defined by a center point and a horizontal and vertical distance, referred to as the span. The span defines how much of the map should be visible and is also how you set the zoom level. For example, specifying a large span results in the user seeing in a wide geographical area at a low zoom level, whereas specifying a small span results in a more narrow geographical area and a higher zoom level..

 

요약하면 지도 정보를 보여주고 조작할 수 있게한다. 원하는 좦표에 지도가 보이게 할 수 있고, 지역 크기를 한정하거나, 지도에 정보를 지정할 수 있다.

 

자세한 구현은 여기서 보면 될거 같다. [https://www.raywenderlich.com/548-mapkit-tutorial-getting-started]

 

 

 

 


 

 

CLGeoCoder() - ios 주소 찾기

 

위도 경도만 찾으면 사실 밑에처럼 고정된 메소드인 recerseGeocodeLocation으로 찾는건 다 똑같은거 같다. 

그런데 한국어로 출력하려면 preferredLocale을 고려하자.

 

 public func getCurrentAddress(group : DispatchGroup){
        let geoCoder : CLGeocoder = CLGeocoder()
        let location : CLLocation = CLLocation(latitude: currentLocation.latitude, longitude: currentLocation.longitude)
        //이걸 넣어야 한국어 주소가 나오네
        let locale = Locale(identifier: "Ko-kr")
        
        
        group.enter()
        //why unowned self declared in []??
        DispatchQueue.global(qos: .userInitiated).async(group: group, execute: { [unowned self] in
             
            
            geoCoder.reverseGeocodeLocation(location, preferredLocale: locale , completionHandler: { (placemark,error) -> Void in
                guard error == nil, let place = placemark?.first else{
                    group.leave()
                    fatalError("error, conver GEO location")
                }
                
                print("got current location")
                
                
                if let administrativeArea : String = place.administrativeArea { self.currentAddress.append(administrativeArea + " " )}
                if let locality : String = place.locality { self.currentAddress.append(locality + " ")}
                if let subLocality : String = place.subLocality { self.currentAddress.append(subLocality + " ")}
                if let subThoroughfare : String = place.subThoroughfare { self.currentAddress.append(subThoroughfare + " ")}
                
                
                
                group.leave()
            })   
        })
        
    }