Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[맛집지도] Hemg #8

Open
wants to merge 48 commits into
base: james_review
Choose a base branch
from
Open

[맛집지도] Hemg #8

wants to merge 48 commits into from

Conversation

hemg2
Copy link
Owner

@hemg2 hemg2 commented Oct 18, 2023

안녕하세요 제임스(@inwoodev)
잘부탁드립니다.

구현 화면

  • 메인뷰 -> 카카오 지도 화면

    • 맛집 음식점 표시
    • 나의 위치로 전환
    • 맛집 리스트로 전환
  • AddVC -> 원하는곳 누른상태에서 마커 커스텀 진행

    • 마커 커스텀하여 표시 진행
    • CRUD 구현 진행
  • ListVC -> 맛집 지도 -> 리스트로 변형

고민했던점

  • 내가 만드는 맛집 지도라는점에서 지도를 커스텀 해야겠다고 생각을 하게 되어 선택한 위치에 지도 마커를 만들수있게 진행했습니다.(CRUD구현)
 protocol AddRestaurant: AnyObject {
    func didAddRestaurants(title: String, description: String, category: RestaurantCategory)
    func didEditRestaurant(title: String, description: String, index: Int, category:
RestaurantCategory)
    func deletePin(withTag tag: Int)
}
  • CLLocationManager 나의 위치
    • 메서드를 통해서 지도 이동 이후에 중심점이 변경된 지점에서 다시 서버 통신을하게 될때 나의 위치가 처음 시작위치에서 변경되지 않아 통신의 문제
 func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
        if let location = locations.last {
            let latitude = location.coordinate.latitude
   ......

CLLocation 메서드를 쓰지않고 나의 위치로 이동할수있는 메서드를 구현하여 이동시 중심점 이동 가능, 이동한곳에서 서버통신 가능하게끔 진행

  private func moveToMyLocation() {
        if let location = locationManager.location?.coordinate {
            let userLocation = MTMapPoint(geoCoord: .init(latitude: location.latitude, longitude: location.longitude))
            mapView.setMapCenter(userLocation, animated: true)
        }
    }
  • 객체관리
    Restaurant값, MTMapPOIItem값 따로 저장을 하다보니 인덱스 이슈로 수정 및 삭제 처리 안되었습니다.
struct Restaurant {
    var title: String
    var description: String
}
   func didAddRestaurants(title: String, description: String) {
      let newRestaurants = Restaurant(title: title, description: description)
      self.restaurantList.append(newRestaurants)
      
      let newPoint = MTMapPOIItem()
      newPoint.itemName = title
      newPoint.userObject = description as NSObject
      newPoint.mapPoint = mapPointValue
      newPoint.markerType = .redPin
      poiItems.append(newPoint)
      mapView?.addPOIItems([newPoint])
      
      mapView?.setMapCenter(mapPointValue, zoomLevel: 2, animated: true)
  }

    private func setUpItemText() {
        guard let titleText = titleTextField.text,
              let descriptionText = descriptionTextView.text else { return }
            let newPoint = MTMapPOIItem()
            newPoint.itemName = title
            newPoint.mapPoint = mapPoint
            newPoint.markerType = .redPin
            
            delegate?.didAddRestaurants(title: titleText, description: descriptionText)
  • 이러한 문제를 해결하기위해 하나로 합치면 인덱스가 같아 질꺼같아 하나로 묶어서 진행하게 되었습니다.
struct RestaurantItem {
    var restaurant: Restaurant
    var poiItem: MTMapPOIItem
}

 func didAddRestaurants(title: String, description: String, category: RestaurantCategory) {
        let newRestaurants = Restaurant(title: title, description: description, category: category)
        let newPoint = MTMapPOIItem()
        newPoint.itemName = title
        newPoint.userObject = description as NSObject
        newPoint.mapPoint = mapPointValue
   let restaurantItem = RestaurantItem(restaurant: newRestaurants, poiItem: newPoint)
        restaurantItems.append(restaurantItem)

해결하지못한점

  • 나의 위치 나침반모드 진행시
 private func setUpMap() {
        mapView = MTMapView(frame: self.view.frame)
     .....
        mapView.currentLocationTrackingMode = .onWithHeadingWithoutMapMoving --- >>> 
This method can cause UI unresponsiveness if invoked on the main thread. Instead, consider waiting for the `-locationManagerDidChangeAuthorization:` callback and checking `authorizationStatus` first.(보라색 문구)
    }

여기서의 보라색문구로 에러가 나타나는데 DispatchQueue.global()//main 을 하더라도 문제가 해결되지않고있습니다.
추가적으로 Info에 권한을 요청을진행했지만 문제가 유지되고있습니다ㅠ

Privacy - Location When In Use Usage Description
Privacy - Location Always Usage Description
Privacy - Location Always and When In Use Usage Description
통신 이동후 통신

@hemg2 hemg2 requested a review from inwoodev October 18, 2023 05:37
Copy link
Collaborator

@inwoodev inwoodev left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@hemg2 안녕하세요~ 프로젝트 수행하시느라 고생이 많으셨습니다.

먼저 이 부분 말씀 드려야 겠어요!
프로젝트를 실행하려 하였으나 다음과 같은 오류가 나서 빌드가 안돼서 아쉬운데로 리뷰를 진행하였어요
There is no XCFramework found at '/Users/~~/Downloads/DaumMap.xcframework'.

커밋과정에서 누락된 부분인듯 하니 이 부분을 수정 해 주시면 한 번 앱 돌려보면서 저도 해결하지 못하신 부분을 같이 고민 해 볼 수 있을듯합니다~

자세한 리뷰는 코멘트를 확인 해 주시고 혹시나 질문이 있으시다면 편하게 dm이나 댓글 남겨주시면 좋을 듯 합니다 :)

Comment on lines +5 to +6
<key>KAKAO_APP_KEY</key>
<string>31dc6fed9ccc85383fbd38f932039bb1</string>
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

오 api키를 이렇게 깃헙에 올리는건 보안 측면에서 적절치 못한 것 같아요. 더 나은 방향으로 저라면 수정 해 볼 것 같아요~!!

Comment on lines 8 to 41
final class LocationNetWork {
private let session: URLSession
let api = LocationAPI()

init(session: URLSession = .shared) {
self.session = session
}

func getLocation(by mapPoint: MTMapPoint, completion: @escaping (Result<Data, URLError>) -> Void) {
guard let url = api.getLocation(by: mapPoint).url else {
completion(.failure(URLError(.badURL)))
return
}

let request = api.request(url: url)

session.dataTask(with: request) { data, _, error in
if error != nil {
completion(.failure(URLError(.cannotLoadFromNetwork)))
} else if let data = data {
completion(.success(data))
}
}.resume()
}

func decodeLocationData(data: Data) -> Result<LocationData, URLError> {
do {
let locationData = try JSONDecoder().decode(LocationData.self, from: data)
return .success(locationData)
} catch {
return .failure(URLError(.cannotParseResponse))
}
}
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LocationNetwork 객체의 로직 플로우를 살펴보니

LocationNetwork의 getLocation을 MainVC에서 실행한 뒤
받은 데이터를 다시 LocationNetwork 객체에서 디코딩을 진행하네요!

아예 하나의 메서드로 통일해서 LocationData를 반환을 하거나 아니면 다른 객체에게 디코딩 책임을 맡기는 게 적절치 않나 생각이 드는데 어떻게 생각하시나요~?

Comment on lines +170 to +173
private func showListView() {
let listViewController = ListViewController()
navigationController?.pushViewController(listViewController, animated: true)
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

지금은 LocationDataManager 라는 싱글턴을 활용하여 MainVC 와 ListVC간에 데이터 공유가 이어지는데요.

음 그냥 해당 함수에서 주입하는 방향으로 수정하여 로직을 개선해 볼 수 있지 않나 생각이 듭니다.

일단 싱글턴은 많이 알려진 안티패턴이기에 정말로 꼭 필요한 상황에서 사용해야 한다고 생각해요. 그런 의미에서 LocationDataManager의 싱글턴 활용은 한 번 더 생각 해 볼만한 문제 같습니다.

Comment on lines 12 to 52
private let searchBar: UISearchBar = {
let searchBar = UISearchBar()
searchBar.searchBarStyle = .minimal
searchBar.backgroundColor = .white
searchBar.placeholder = "식당 검색"
searchBar.translatesAutoresizingMaskIntoConstraints = false

return searchBar
}()

private let currentLocationButton: UIButton = {
let button = UIButton()
button.setImage(UIImage(systemName: "location.fill"), for: .normal)
button.backgroundColor = .white
button.layer.cornerRadius = 20
button.translatesAutoresizingMaskIntoConstraints = false

return button
}()

private let requestButton: UIButton = {
let button = UIButton()
button.setTitle("맛집!", for: .normal)
button.setTitleColor(.black, for: .normal)
button.backgroundColor = .white
button.layer.cornerRadius = 20
button.translatesAutoresizingMaskIntoConstraints = false

return button
}()

private let listButton: UIButton = {
let button = UIButton()
button.setTitle("목록", for: .normal)
button.setTitleColor(.black, for: .normal)
button.backgroundColor = .white
button.layer.cornerRadius = 20
button.translatesAutoresizingMaskIntoConstraints = false

return button
}()
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

MainVC가 비대해지는 이유중 하나가 요런 뷰 관련 세팅도 한 몫 한다고 생각해요~

loadView 시점에서 mainView를 세팅 해 주면 VC의 코드양도 줄이고 로직 파악이 더 수월해질 수 있다고 생각하기에 하나의 좋은 방법인 것 같아요!

Comment on lines +8 to +24
struct Document: Decodable {
let placeName: String
let addressName: String
let roadAddressName: String
let x: String
let y: String
let distance: String
let categoryName: String

enum CodingKeys: String, CodingKey {
case x, y, distance
case placeName = "place_name"
case addressName = "address_name"
case roadAddressName = "road_address_name"
case categoryName = "category_name"
}
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Document란 이름이 조금 추상적이어서요 저라면 좀 더 나은 네이밍을 고민해볼 것 같아요!


private func fetchLocationData() {
self.locationData = LocationDataManager.shared.locationData
tableView.reloadData()
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

tableView의 reloadData()를 하지 않으면 정상적으로 화면을 그릴 수 없는 상황으로 예상됩니다(빌드 오류 때문에 앱 실행이 안되어서요. 음 그럼 만약에 다른 비슷한 상황에서 reload 메서드를 까먹으면요?

Comment on lines +94 to +97
if let intDistance: Int = Int(distance) {
return Int(intDistance * 2)
}
return 0
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

계산을 하는 과정이 많죠~ 이 책임을 다른 객체에게 부담하게 하는 방향은 어때요?

Comment on lines +258 to +269
switch status {
case .authorizedAlways,.authorizedWhenInUse:
print("GPS 권한 설정됨")
case .restricted,.notDetermined:
print("GPS 권한 설정되지 않음")
getLocationUsagePermission()
case .denied:
print("GPS 권한 요청 거부됨")
getLocationUsagePermission()
default:
print("GPS:Default")
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

요런 에러들은 UI로 보여줘서 유저 편의성을 높일 수 있어 보여요~

Comment on lines +222 to +226
let addViewController = AddViewController(restaurantList: restaurant, mapPoint: poiItem.mapPoint, index: poiItem.tag)
let navigationController = UINavigationController(rootViewController: addViewController)

addViewController.delegate = self
self?.present(navigationController, animated: true)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

addViewController를 새로운 네비게이션 컨트롤러에 embed시키는 이유가 혹시 navigationItem 때문일까요? 만약 그것만이 이유라면 다른 방법을 찾아 볼 수 있을 듯 해서요~!

Comment on lines 145 to 150
case .failure(let error):
print(error)
}

case .failure(let error):
print(error)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

다른 코멘트와 겹치는 부분인듯한데요~ 이 부분은 유저는 몰라도 된다고 생각하실까요~?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants