맨 처음 어플을 제작하는 과정에선 카카오맵을 사용했었다. 이유는 카카오 로그인 기능을 사용하면서 카카오 sdk를 설치했는데, 로그인 기능과 맵 기능을 같이 설치할 수 있을거 같아서다.
그런데 카카오맵은 우선 objective-c 언어를 기본으로 구현되어있고, 그래도 변환이 가능하긴 하지만 맵 마커 기능이 제대로 구현이 안되는 것 같았다. LostItem에서는 마커를 자유롭게 사용할 수 있는 것이 핵심 기능이기 때문에 Naver Map으로 변경했다.
맵을 구현하는데 두 가지 종류가 있다. 우선은 NMFNaverMapView가 더 상위호환 버전이라고 생각하면 쉽다. 모든 기능과 최신업데이트를 사용한다. 반면 NMFMapView는 좀 더 간소화 된 인터페이스를 제공하며 맵 제공이외에 별다른 기능이 필요없다면 채택할만 하다.
나는 마커 기능, 현재 위치 기능이 필요하기 때문에 NMFNaverMapView를 채택했다.
맵 구현 자체는 공식 문서를 따라한다면 큰 어려움 없이 구현이 가능하다. 그러나 본 프로젝트에서 문제는 마커 기능 구현이었는데,
와 같이 단순하지않은 작업이다.
내가 이 과정을 구현한 방식은 게시글을 작성한 후 (게시글 작성 관련된 것은 후에 따로 작성할 예정) 맵 중앙에 사용자가 임시 마커를 확인할 수 있으며, 맵을 임의로 이동시켜 마커를 원하는 위치에 고정시켜 게시글 작성 및 좌표를 저장한다.
FireStore 이용
func saveCenterCoordinates() {
if let subView = subView { // subView 변수가 올바른지 확인
let centerX = subView.frame.width / 2
let centerY = subView.frame.height / 2
// 중앙 좌표를 화면 좌표부터 지도 좌표로 변환
let centerLatLng = subView.mapView.projection.latlng(from: CGPoint(x: centerX, y: centerY))
// Firestore 데이터베이스에 접근
let db = Firestore.firestore()
// "게시글" 컬렉션에 좌표를 저장
let data: [String: Any] = [
"latitude": centerLatLng.lat,
"longitude": centerLatLng.lng
// 다른 필요한 데이터도 함께 저장
]
let collectionRef = db.collection("게시글")
let documentRef = collectionRef.document(self.titleLabel)
documentRef.getDocument { (document, error) in
if let document = document, document.exists {
// 문서가 존재하면 업데이트 작업 수행
documentRef.updateData(data) { err in
if let err = err {
print("Error updating document: \(err)")
} else {
print("Document updated")
}
}
}
}
}
}
이렇게 좌표를 저장한 후, 이 좌표를 마커로 변환 해주는 것을 진행한다.
// Firestore에서 "게시글" 컬렉션의 문서를 가져와서 좌표 데이터 필드를 네이버지도의 마커로 표시
func fetchMarkersFromFirestore() {
let db = Firestore.firestore()
let collectionRef = db.collection("게시글")
collectionRef.getDocuments { (snapshot, error) in
if let error = error {
print("Error getting documents: \(error.localizedDescription)")
return
}
guard let documents = snapshot?.documents else {
print("No documents found.")
return
}
// 각 문서에서 좌표 데이터 필드를 추출하고 네이버지도의 마커로 표시
for document in documents {
let data = document.data()
if let latitude = data["latitude"] as? Double,
let longitude = data["longitude"] as? Double {
// 좌표를 이용하여 네이버지도의 마커를 생성하고 추가
let marker = NMFMarker()
marker.position = NMGLatLng(lat: latitude, lng: longitude)
marker.mapView = self.subView.mapView
//마커 이미지 및 크기 지정
marker.iconImage = NMFOverlayImage(name: "free-icon-lost-items-3372390-3.png")
marker.width = 30
marker.height = 30
let storyboard = UIStoryboard(name: "Register", bundle: nil)
guard let PostViewControllerVC = storyboard.instantiateViewController(withIdentifier: "PostViewController") as? PostViewController else { return }
// 마커를 탭할시 정보창 보여줌
let handler = { [weak self] (overlay: NMFOverlay) -> Bool in
if let marker = overlay as? NMFMarker {
// 현재 마커에 정보 창이 열려있지 않을 경우 엶
PostViewControllerVC.latitude = marker.position.lat
PostViewControllerVC.longitude = marker.position.lng
self?.present(PostViewControllerVC, animated: true)
PostViewControllerVC.deleteBtn.isHidden = true
PostViewControllerVC.ChatButton.isHidden = false
let db = Firestore.firestore()
db.collection("게시글")
.whereField("latitude", isEqualTo: latitude)
.whereField("longitude", isEqualTo: longitude)
.getDocuments { (querySnapshot, error) in
if let error = error {
print("Error fetching documents: \(error)")
return
}
if let document = querySnapshot?.documents.first {
// 문서가 존재하면 필드 값을 가져와 화면에 표시
let documentID = document.documentID
PostViewControllerVC.titleLabel.text = documentID
if let chatuser = document["유저"] as? String {
PostViewControllerVC.chatUser = chatuser
}
}
}
}
return true
};
marker.touchHandler = handler
}
}
}
}
마커의 이미지 및 크기를 지정해주고 FireStore에 저장했던 좌표를 기준으로 마커를 지정해준다.
그리고 또 중요했던 점은 touch handler를 사용하여 마커를 클릭했을때 액션을 만들 수 있다.
해당 앱에서는 마커를 클릭했을시 분실물의 정보들을 가진 Post를 present형식으로 나오게끔 하였다.
UI 구성전 간단한 예시 사진)