🧑💻 숙련 주차 팀 프로젝트
오늘은 팀프로젝트 4일차이다.
오늘 구현할 내용은 마커 등록이다.
마커를 등록하기 위해서는 CoreData를 사용해서 위도와 경도 값을 디바이스에 저장하고
저장된 위도와 경도 값을 불러와서 마커로 표시해주면 된다.
추가로 gps 버튼을 누르면 현재 위치로 지도를 이동하게 하는 것도 구현하였다.
그리고 지도를 마우스로 선택하면 위도와 경도를 받아와서 textView에 표시하고 등록하는 것도 구현하였다.
🗺️ 지도의 기본 위치 값 변경하기
네이버 Map API를 이용하여 지도를 표시할 때
아무런 설정을 해주지 않으면 기본적으로 네이버 본사가 위치한 판교 정자역 근처 중심으로 지도가 표시된다.
나는 지도의 기본 위치를 홍대입구역으로 바꾸기 위해 코드를 추가 작성하였다.
lazy var mapView: NMFMapView = {
let mapView = NMFMapView(frame: self.view.frame)
let cameraPosition = NMFCameraPosition(
NMGLatLng(lat: 37.557116, lng: 126.924353), // 좌표
zoom: 15.0, // 줌 레벨
tilt: 0.0, // 기울기 (tilt)
heading: 0.0 // 방향 (bearing)
)
let cameraUpdate = NMFCameraUpdate(position: cameraPosition)
mapView.moveCamera(cameraUpdate)
return mapView
}()
📍 마커 추가하기
마커 · NAVER Map iOS SDK
No results matching ""
navermaps.github.io
마커는 지도상의 한 지점을 나타내기 위한 오버레이로, 지도에서 가장 널리 사용되는 요소이다.
마커를 사용하면 특정 지도상 좌표에 아이콘과 캡션을 표시할 수 있다.
마커의 아이콘과 캡션은 지도와 함께 움직이지만 지도를 확대 또는 축소 하더라도 일정한 형태를 유지한다.
또한 마커는 터치 이벤트를 받을 수 있으며 이벤트를 소비하거나 지도로 전파할 수도 있습니다.
마커를 추가하는 방법은 간단하다.
NMFMarker를 통해 인스턴스를 생성하고
marker의 위치를 설정하고
mapView를 지정하면 지도에 마커가 추가된다.
// 지도에 마커를 추가하는 함수
private func displayKickBoardMarkers(on mapView: NMFMapView, with data: [KickBoardModel]) {
for kickBoard in data {
// 인스턴스 생성
let marker = NMFMarker()
// 마커가 생성될 경도와 위도 설정
marker.position = NMGLatLng(lat: kickBoard.lat, lng: kickBoard.lon)
// 마커에 표시될 아이콘 이미지 설정
marker.iconImage = NMFOverlayImage(name: "markerImage")
// mapView를 지정
marker.mapView = mapView
}
}
[ 지도 생성시 마커 생성과 위도와 경도를 입력하고 등록하기 버튼을 눌렀을 때 마커 생성 ]
💽 CoreData와 연결하여 사용하기
[ CoreDataManager.swift 전체 코드 ]
//
// CoreDataManager.swift
// SwiftKickBoard
//
// Created by 허성필 on 4/30/25.
//
import Foundation
import CoreData
import UIKit
class CoreData {
static let shared = CoreData()
var container: NSPersistentContainer!
private init() {
let appDelegate = UIApplication.shared.delegate as! AppDelegate
self.container = appDelegate.persistentContainer
}
// CoreData 데이터 저장하기
func createData(id: Int, lat: Double, lon: Double) {
guard let entity = NSEntityDescription.entity(forEntityName: KickBoard.className, in: self.container.viewContext) else { return }
let newContacts = NSManagedObject(entity: entity, insertInto: self.container.viewContext)
newContacts.setValue(id, forKey: KickBoard.Key.id)
newContacts.setValue(lat, forKey: KickBoard.Key.lat)
newContacts.setValue(lon, forKey: KickBoard.Key.lon)
do {
try self.container.viewContext.save()
print("킥보드 등록 성공")
} catch {
print("킥보드 등록 실패")
}
}
// CoreData 저장된 데이터 선택 삭제
func deleteData(id: Int) {
// 삭제할 데이터를 찾기 위한 fetch request 생성
let fetchRequest = KickBoard.fetchRequest()
fetchRequest.predicate = NSPredicate(format: "id == %@", id)
do {
// fetch request 실행
let result = try self.container.viewContext.fetch(fetchRequest)
// 결과 처리
for data in result as [NSManagedObject] {
// 삭제
// CRUD 의 D.
self.container.viewContext.delete(data)
print("삭제된 데이터: \(data)")
}
// 변경 사항 저장
try self.container.viewContext.save()
print("데이터 삭제 완료")
} catch {
print("데이터 삭제 실패: \(error)")
}
}
// CoreData 저장된 데이터 읽어오기
func readAllData() -> [KickBoard] {
do {
let kickBoard = try self.container.viewContext.fetch(KickBoard.fetchRequest())
return kickBoard
} catch {
print("데이터 읽기 실패")
return []
}
}
}
[ 1. shared를 사용하여 싱글톤 패턴 사용 ]
static let shared = CoreData()
[ 2. private 생성자 ]
// 싱글톤 패턴은 private 생성자 사용
private init() {
let appDelegate = UIApplication.shared.delegate as! AppDelegate
self.container = appDelegate.persistentContainer
}
[ 3. CoreData 등록 함수 ]
// CoreData 데이터 저장하기
func createData(id: Int, lat: Double, lon: Double) {
guard let entity = NSEntityDescription.entity(forEntityName: KickBoard.className, in: self.container.viewContext) else { return }
let newContacts = NSManagedObject(entity: entity, insertInto: self.container.viewContext)
newContacts.setValue(id, forKey: KickBoard.Key.id)
newContacts.setValue(lat, forKey: KickBoard.Key.lat)
newContacts.setValue(lon, forKey: KickBoard.Key.lon)
do {
try self.container.viewContext.save()
print("킥보드 등록 성공")
} catch {
print("킥보드 등록 실패")
}
}
[ 4. CoreData 삭제 함수 ]
// CoreData 저장된 데이터 선택 삭제
func deleteData(id: Int) {
// 삭제할 데이터를 찾기 위한 fetch request 생성
let fetchRequest = KickBoard.fetchRequest()
fetchRequest.predicate = NSPredicate(format: "id == %@", id)
do {
// fetch request 실행
let result = try self.container.viewContext.fetch(fetchRequest)
// 결과 처리
for data in result as [NSManagedObject] {
// 삭제
// CRUD 의 D.
self.container.viewContext.delete(data)
print("삭제된 데이터: \(data)")
}
// 변경 사항 저장
try self.container.viewContext.save()
print("데이터 삭제 완료")
} catch {
print("데이터 삭제 실패: \(error)")
}
}
[ 5. CoreData 읽기 함수 ]
// CoreData 저장된 데이터 읽어오기
// AddViewController 에서 사용하기 위해 [KickBoard] 리턴
func readAllData() -> [KickBoard] {
do {
let kickBoard = try self.container.viewContext.fetch(KickBoard.fetchRequest())
return kickBoard
} catch {
print("데이터 읽기 실패")
return []
}
}
🖱️ 지도 클릭 이벤트 추가 구현
AddViewController에 NMFMapTouchDelegate 추가
class AddViewController: UIViewController, NMFMapViewTouchDelegate {
// 지도를 클릭하면 호출되는 델리게이트 메서드
func mapView(_ mapView: NMFMapView, didTapMap latlng: NMGLatLng, point: CGPoint) {
let lat = latlng.lat
let lon = latlng.lng
print("지도 클릭 : 위도 \(lat), 경도 \(lon)")
xTextField.text = "\(lat)"
yTextField.text = "\(lon)"
}
}
해당 메서드 추가로 사용자가 지도 위에서 클릭한 부분의 위도와 경도를 받아오고
받아온 위도와 경도를 textField에 각각 입력해주는 로직을 구현하였다.
'스파르타 코딩 클럽 - iOS 스타터 6기 > 본 캠프' 카테고리의 다른 글
44. 스파르타 코딩 클럽 - Xcode Instruments, 동기 / 비동기 (0) | 2025.05.08 |
---|---|
43. 스파르타 코딩 클럽 - 킥보드 대여 앱 만들기 (5) (0) | 2025.05.01 |
41. 스파르타 코딩 클럽 - 킥보드 대여 앱 만들기 (3) (0) | 2025.04.29 |
40. 스파르타 코딩 클럽 - 킥보드 대여 앱 만들기 (2) (0) | 2025.04.28 |
39. 스파르타 코딩 클럽 - 킥보드 대여 앱 만들기 (1) (1) | 2025.04.25 |