Ch.6 Silver: Displaying the User’s Region

# 유저의 위치 나타내기

  • 지도에 현재 유저의 위치를 줌인해서 보여주는 게 과제!
  • 유저로부터 위치 정보 사용을 승인 받고, 승인되는 경우 줌인하도록 구현했다.

# 위치 정보 사용 동의 받기

1. Info.plist 에 "Privacy-Location When In Use Usage Description" 키 추가

  • 얘의 역할은 위치 정보 사용 동의를 받을 때 유저에게 나타낼 메시지를 설정할 수 있게 해준다.
    • value 에 나타낼 메시지를 적으면 된다!
  • 주의할 점은 "When In Use" 일 때, 즉 앱이 실행되고 있을 때의 위치 정보 접근 권한을 요청하는 경우에만 알림창을 띄운다는 것
  • 즉, requestWhenInUseAuthorization() 메서드를 호출할 때만 알림을 띄우고, requestAlwaysAuthorization() 메서드를 호출하면 아무것도 띄우지 않는다.

2. CLLocationManager 오브젝트로 위치 접근 권한 요청하기

  • 얘는 위치 관련 이벤트를 관리하는 역할로, 유저에게 위치 접근 권한을 요청할 수 있는 requestWhenInUseAuthorization() 메서드를 포함하고 있다.
  • requestWhenInUseAuthorization() 메서드가 호출되면 아래와 같은 알림창이 뜨는 데, 유저가 허용 여부를 선택하면 델리게이트의 locationManagerDidChangeAuthorization(_:) 가 호출된다.
    • 따라서 MapViewController 를 CLLocationManagerDelegate 프로토콜에 따르게 하고 CLLocationManager 오브젝트의 델레게이트로 선언해 locationManagerDidChangeAuthorization(_:) 메서드에 권한에 따라 작업을 수행하도록 한다.

      • CLLocationManager 타입의 locationManager 프로퍼티를 선언한 다음 viewDidLoad() 함수에서 초기화하고 델리게이트를 지정했다.

      • 그 다음 requestWhenInUseAuthorization() 메서드를 호출하고, 이에 따라 호출 될 locationManagerDidChangeAuthorization(_:) 메서드에서 authorization status 를 확인해서 .authorizedWhenInUse 인 경우 지도에서 유저의 위치를 계속 추적해서 업데이트할 수 있도록 showsUserLocation 프로퍼티를 토글했다.
import UIKit
import MapKit

class MapViewController: UIViewController, CLLocationManagerDelegate {
    private var mapView: MKMapView!
    private var locationManager: CLLocationManager!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        locationManager = CLLocationManager()
        locationManager.delegate = self
        locationManager.requestWhenInUseAuthorization()
        print("MapViewController loaded its view")
    }

    func locationManagerDidChangeAuthorization(_ manager: CLLocationManager) {
        if manager.authorizationStatus == .authorizedWhenInUse {
            mapView.showsUserLocation.toggle()
        }
    }
}

# 사용자의 위치에 줌인하기

  • 위의 단계까지 하면 지도에 사용자의 위치가 파란 점으로 표시는 되는데 줌인이 안 된 상태다. setRegion(_:animated) 메서드를 사용하면 디스플레이 되는 지역을 바꿀 수 있고, 첫 번째 인자의 설정을 통해 줌 정도를 변경할 수 있다.
  • 따라서 유저의 위치가 바뀔 때마다 setRegion(_:animated) 메서드를 호출하면 되는데, 유저의 위치가 업데이트 될 때마다 이에 대한 알림을 받기 위해서는 mapview 델레게이트의 메서드 중 mapView(_:didUpdate:) 메서드를 사용할 수 있다.
  • 즉, MapViewController 를 mapView 의 델리게이트로 선언한 다음, mapView(_:didUpdate:) 메서드에서 setRegion(_:animated) 메서드를 호출하게 하면 유저의 위치가 바뀔 때마다 유저의 현재 위치로 줌인하게 할 수 있다.

  • mapView(_:didUpdate:) 메서드에서 setRegion(_:animated) 메서드를 바로 호출하게 하지 않고 별도로 zoomIntoUserLocation(userLocation:) 메서드를 사용해서 구현했는데, center 가 userLocation 의 좌표와 일치하고, span 이 0.01 인 MKUserLocation 오브젝트를 생성해 setRegion(_:animated) 메서드의 인자로 보냈다.

    • span 은 0 일때 최대로 줌인된 상태!
class MapViewController: UIViewController, CLLocationManagerDelegate, MKMapViewDelegate {
    private var mapView: MKMapView!
    private var locationManager: CLLocationManager!
    
    override func loadView() {
        super.loadView()
        
        mapView = MKMapView()
        view = mapView
        mapView.delegate = self  // 델리게이트 설정
        ...
    }
    
    func mapView(_ mapView: MKMapView, didUpdate userLocation: MKUserLocation) {
        zoomIntoUserLocation(userLocation: userLocation)
    }
    
    private func zoomIntoUserLocation(userLocation: MKUserLocation) {
        let locationDegrees: Double = 0.01
        let region = MKCoordinateRegion(
            center: userLocation.coordinate,
            span: MKCoordinateSpan(
                latitudeDelta: locationDegrees,
                longitudeDelta: locationDegrees
            )
        )
        mapView.setRegion(region, animated: true)
    }
}

☀️ 느낀점

  • 이번 과제를 하면서 델리게이트의 가치에 대해 배울 수 있었다. 사실 델리게이트의 개념조차도 아직 확실하게 이해한 게 아니라서 처음에는 왜 델리게이트 설정을 해줘야하는지 궁금했는데(얼렁뚱땅으로 코드를 짰는데 델리게이트 없이 수동으로도 과제에서 요구하는 바를 구현할 수는 있었기 때문에...) 델리게이트의 메서드를 활용하면 더 깔끔하게 코드를 작성할 수 있다는 점을 배웠다.

    • 줌인을 할 때 처음에는 userLocation 프로퍼티를 따로 선언하고 didSet 을 사용해서 위치가 바뀔 때마다 setRegion(_:animated) 메서드를 호출하려고 했는데, mapView(_:didUpdate:) 메서드를 활용하면 어차피 유저의 위치가 바뀔 때마다 해당 메서드가 호출되므로 프로퍼티 선언이나 didSet 호출의 과정이 필요없었다...!

좋은 웹페이지 즐겨찾기