날씨앱을 만들면서 필수적으로 해야한다고 생각했던 것이
유저의 위치를 파악하고, 파악한 해당 위치의 좌표를 활용해 기상청 API에 데이터를 요청하고,
앱에 사용자의 현재 장소를 표시해주려고 하는데요
그러기 위해서는 CoreLocation을 사용해보았습니다!
제대로 사용해보는건 처음이라서 시행착오도 조금 있었지만
잘 작동하는 것 같아 정리해보려 합니다!
https://developer.apple.com/documentation/corelocation
https://developer.apple.com/documentation/corelocation/getting_the_current_location_of_a_device
우선 info.plist에 위치 사용 권한을 추가해줍니다.
그리고 앱 전반적으로 사용할 locationManager를 싱글톤으로 만들었습니다.
싱글톤으로 만들어서 위치 관련 로직은 여기에 다 넣고, 앱 전역에서 쉽게 접근하려 했습니다!
lazy var longitude 와 lazy var latitude는 locationManager가 처음 좌표를 얻어오면 저기에 저장이 되고,
func setNxNy(nx: String, ny: String)함수를 통해 String으로 변환해 기상청 API 요청에 사용할 수 있도록 만들었습니다.
그런데 여기서 문제는 앱을 시작할때 로딩을 하면서 바로 기상청 API가 호출되는데
그 전에 locationManager를 사용해서 좌표를 가져오고, 가져온 좌표를 활용해 기상청 API를 호출해야 되는 것이었습니다..
그래서 비동기 함수도 만들어보고..이것저것 해보고 고민을 해보다가..
어차피 앱 전반적으로 위치데이터는 활용되고, 위치 동의도 받아야 하니
AppDelegate에서 didFinishLaunchingWithOptions에 넣어보기로 했습니다.
(제 맘대로 해본거라 맞는지는 모르겠지만 더 좋은 방법이 있으시면 댓글로 알려주세요!)
delegate 설정을 해주고 유저 동의 요청까지 넣어줍니다!
그리고 extension에서 세 함수를 사용했습니다.
func locationManagerDidChangeAuthorization(_ manager: CLLocationManager) 에서
CLLocationManager.locationServicesEnabled()를 통해
유저가 위치정보에 동의했는지 확인하고, 동의했을때 위치정보를 받아옵니다!
받아온 위치정보를 LocationService에 저장합니다.
받아올때는 비동기함수로, global큐에서 데이터를 받아옵니다.
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation])함수로
유저가 위치를 이동했을때 좌표를 업데이트할 수 있습니다.
locations는 배열로 주는데 저는 배열의 첫 좌표를 사용했습니다.
업데이트한 좌표를 마찬가지로 LocationService에 넣어줍니다.
마지막으로
func locationManager(_ manager: CLLocationManager, didFailWithError error: Error)
함수를 통해 에러를 확인합니다.
그리고 LocationService에서 func getLocation(location: CLLocation, complition: @escaping (CLLocation) -> Void) 함수를 만들었는데, locationManager에서
self.locationManger.desiredAccuracy = kCLLocationAccuracyHundredMeters 를 통해 위치 정확도를 100미터로 설정하고,
self.locationManger.distanceFilter = 1500 로 1500미터 이동할때마다 위치정보를 업데이트하도록 했습니다.
이 함수들은 꼭 여기에 안있고 아까 함수에 있어도 될 것 같아요!
위치정확도와 업데이트거리는 정확하게 설정할수록 배터리를 많이 잡아먹는다고 하니 필요하신 경우에 따라 조정하시는 것이 좋을 것 같습니다!
이렇게 받아온 위치를 비동기 함수로 보내주고, 받은 데이터를 클로저에서
LocationManager에 있는 func setNxNy(nx: String, ny: String)함수를 사용해 String으로 만들어 기상청 API에서 사용하도록 만들었고,
LocationService.shared.locationToString(location: location)함수를 통해 현재 유저의 위치 주소를 가져오도록 만들었습니다.
기상청 API는 가져온 좌표를 통해 알맞는 데이터를 호출하게 됩니다.
locationToString 함수는 CLGeocoder()를 활용해 현재 위치를 주소로 바꿔줍니다.
CLGeocoder()를 활용해 placemarks를 가져올 수 있는데 이것을 사용자가 원하는 형태로 변경할 수 있습니다.
예를 들면 여기서 locality는 서울특별시, subLocality는 충무로 3가로 앱에서 표시됩니다.
가져온 지역명을 LocationManager변수에 저장하고 나중에 앱에서 활용합니다!
함수는 공식문서 두 가지를 참고해서 만들었습니다!
여기서는 Placemark의 종류를 보실 수 있습니다.
https://developer.apple.com/documentation/corelocation/clplacemark
이렇게 하고 앱을 돌려보면~~
이렇게 위치와 좌표, 주소까지 잘 가져오는 모습을 볼 수 있습니다!
제가 얼마전에 테스트 할겸 대구도 다녀왔는데
이렇게 대구에서도 좌표와 주소가 잘 찍히는 모습을 볼 수 있었습니다
살고있는 아파트이름에 우편번호까지 정확하게 나오길래 조금 놀랐어요..! 생각보다 엄청 정확하네요! 역시 애플...
마지막으로 background에서도 위치를 얻을 수 있도록 해서 나중에 만들 위젯이나 알림에 사용하려 합니다!
https://developer.apple.com/documentation/corelocation/handling_location_updates_in_the_background
정리를 한다고 했는데 내용이 많다보니 깔끔하지는 않은것 같네요..
앞으로 만들면서 중간중간에 더 정리해보도록 하겠습니다!
화이팅!!!