Apple MapKit을 사용하여 지도를 구성하고, 사용자 조작 이벤트를 통해 지도의 중심점이 변경될 때마다 주소(좌표 변환)를 표시하는 label의 내용도 실시간으로 변경되도록 기능을 개발했다.
iOS Simulator에서 빌드를 하고 정상적으로 지도 및 좌표가 표시되었는데, 지도의 중심 위치가 변경됨에 따라 label의 text도 변경되는 것을 확인할 수 있었다.
하지만 지도 조작 과정에서 주소를 표시하는 label의 text가 변경되지 않고 멈추는 문제가 발생했고, 출력되는 log를 확인해 보았다.
Throttled "PlaceRequest.REQUEST_TYPE_REVERSE_GEOCODING" request: Tried to make more than 50 requests in 60 seconds, will reset in 58 seconds - Error Domain=GEOErrorDomain Code=-3 "(null)" UserInfo={details=(
{
intervalType = short;
maxRequests = 50;
"throttler.keyPath" = "app:kr.youngs.NewWDIT/0x20304/short(default/any)";
timeUntilReset = 58;
windowSize = 60;
}
), requestKindString=PlaceRequest.REQUEST_TYPE_REVERSE_GEOCODING, timeUntilReset=58, requestKind=772}
발생한 log는 CLLocation과 관련된 오류였다.
StackOverflow를 찾아보니 다음과 같은 내용을 찾을 수 있었다.
As you make location accuracy to best you get very frequent location update. For each update you try get a reverse location to get the name of the place. This happens too often for the system and that cause your error. You should have a timer fire every few seconds to find reverse location of the current user location saved in your ObservableObject. –
Ptit Xav
위치 업데이트가 시스템에서 너무 자주 발생하여 생긴 오류라고 한다.
로그를 읽어 보면 60초 동안 50회의 요청을 넘어 오류가 발생했다는 것을확인할 수 있다.
서버 과부하를 방지하고 모든 사용자에게 지오코딩 서비스를 공평하게 제공하기 위해 iOS 앱은 짧은 시간에 지정된 횟수의 요청만 할 수 있기 때문이다.
해결 방안으로 2가지 방법을 생각해 보았다.
타이머를 사용하여 마지막 지도 이동 이벤트가 종료되고 일정 시간동안 추가 이벤트가 없을 경우에 주소를 업데이트하는 방법
기존에 조회한 주소는 따로 저장해 두었다가 같은 위치에 주소 요청이 발생하면 저장한 주소를 재사용하는 방법
mapView(_:regionDidChangeAnimated:) 메서드를 사용하여 지도 이동 종료 시점을 감지하고, 해당 시점에서만 주소를 업데이트하는 방법이다.
지도의 뷰가 변할 때마다 호출되는 메서드이기 때문에 추가 로직을 적용해 지도 이동이 완료된 후에 주소가 한 번만 업데이트 되도록 한다.
지도 이동 이벤트 발생 시 해당 좌표에 대한 주소를 캐시(Dictionary)에 저장한다.
지도의 현재 좌표를 키로 사용하여 사전에 저장한 주소인지 확인한다.
현재 좌표가 캐시에 없는 경우, CLGeocoder를 사용하여 주소를 조회하고 결과를 저장한다.
1, 2번 방법을 모두 적용해 보며 어떤 방법이 효율적일지 생각해 보았다.
앱 사용 시간이 짧고 몇 개의 특정 지역을 지도로 탐색하는 경우에는 2번 방법이 효율적이라고 생각했다. 하지만 앱 사용 시간이 길어지고 많은 지역(많은 좌표)를 지도에서 탐색할 경우 2번 방법은 메모리 사용량이 증가할 수 있는 잠재적인 문제를 갖고 있다고 판단했다. 효율적인 측면을 생각했을 경우 타이머를 사용하는 1번의 방법이 캐시를 사용하는 2번의 방법보다 메모리 사용 및 앱 성능 면에서 효율적이라고 생각한다.
보다 더 효율적인 1번 방법을 적용한다면 오류를 해결함과 동시에 CLLocation의 불필요한 네트워크 요청을 줄이고, 메모리를 보다 효율적으로 사용할 수 있다.
https://stackoverflow.com/questions/77017738/swiftui-location-manager