728x90 SMALL Project/HiddenGem14 🤔 여러 ViewController에서 위치 권한을 사용할 경우에는? https://explorer89.tistory.com/423 ✅ 위치 정보 및 권한 설정하기https://explorer89.tistory.com/159 위치정보를 받아오는 방법참고 사이트 https://velog.io/@maddie/iOS-UIKit-CoreLocation-%EC%82%AC%EC%9A%A9%EB%B2%95-%EC%A0%95%EB%A6%AC" data-og-host="velog.io" data-og-source-url="https://velog.io/@maddie/iOS-explorer89.tistory.com 🔍 구현하려는 상황 HomeViewController가 위치 권한 요청 및 위치 갱신 로직을 가지고 있고,LocationSearchViewController는 UISheetPr.. 2025. 6. 10. 🤔 탭바는 가리지 않고, 커스텀 Bottom Sheet처럼 동작하는 UI를 원한다면? ✅ 목표탭바 가리지 않음sheetPresentationController 사용 안 함UIView를 하단에서 슬라이드 업하는 느낌의 Bottom Sheet 형태 구현✅ 구현 구조LocationViewController└ mapView (전체)└ bottomSheetView (하단에서 올라옴) └ 검색창, 버튼 등 원하는 UI ✅ BottomMapView 클래스로 분리된 경우 적용 예시// BottomMapView.swiftclass BottomMapView: UIView { // MARK: - 상태 관리 enum SheetPosition: CaseIterable { case min, mid, max var height: CGFloat { .. 2025. 6. 4. 🔨 Raw value for enum case must be a literal 문제 해결! ❗️문제 원인enum SheetPosition: CGFloat, CaseIterable { case min = 150 case mid = UIScreen.main.bounds.height * 0.4 // ❌ 이 줄 case max = UIScreen.main.bounds.height * 0.85 // ❌ 이 줄} ❗️ 에러 메시지:Raw value for enum case must be a literal→ enum의 raw value는 상수 리터럴만 가능해.UIScreen.main.bounds.height는 런타임에 계산되는 값이라 불가능해. ✅ 해결 방법런타임 계산이 필요한 값을 enum 안에서 computed property로 처리하는 구조로 변경enum SheetPosition: .. 2025. 6. 3. 🤔 뷰 컨트롤러가 모달로 띄워졌는지 어떻게 알 수 있나? ✅ 이 로직이 필요한 이유UIViewController에는 isModal 같은 속성이 없어서,push로 띄웠는지 / present로 띄웠는지 직접 판단해야 합니다. var isModal: Bool { if let navigationController = navigationController { if navigationController.viewControllers.first != self { return false } } if presentingViewController != nil { return true } if navigationController?.presentingViewController?.presentedVi.. 2025. 6. 2. 🗺️ 지도 표시하기 import UIKitimport MapKitclass DetailMapInfoCell: UICollectionViewCell { static let reuseIdentifier: String = "DetailMapInfoCell" // MARK: - UI Components private let containerView: UIView = UIView() private let mapView: MKMapView = MKMapView() private let addressLabel: UILabel = UILabel() private let mapExpandButton: UIButton = UIButton() override init(frame: CGRect.. 2025. 6. 2. 🔨 데이터 타입 변환 및 통합하기 ✅ 여러 데이터 타입을 하나의 데이터 타입으로 통합하기 통합하는 이유는 추후체 컬렉션뷰를 사용함에 있어서 데이터 관리 용이성 확보 및, 컬렉션뷰의 품질 향상 목적// 📍 detail 정보 { "response": { "header": { "resultCode": "0000", "resultMsg": "OK" }, "body": { "items": { "item": [ { "contentid": "126128", "contenttypeid": "12", "heritage1": "0", "heritage2": "0", "heritage3.. 2025. 5. 29. ✅ UICollectionViewCell을 공용으로 사용하려면? (데이터 타입도 다를때) ✅ 현재 셀을 보면 공용으로 사용되는 것을 확인할 수 있음 따라서 먼저 각 셀의 UI를 공용으로 사용할 수 있도록 하나의 클래스를 생성함 /// 상세페이지 내에 각 셀에 공용으로 사용될 UIfinal class TitleValueView: UIView { // MARK: - UI Component private let titleLabel: UILabel = UILabel() private let valueLabel: BasePaddingLabel = BasePaddingLabel() init(title: String = "", value: String = "") { super.init(frame: .zero) setupUI() .. 2025. 5. 27. 🤷 컬렉션뷰에 페이징 기능 추가 (스크롤하면 새 데이터 불러와 컬렉션뷰로 보여주기) ✅ 최종 구현 영상컬렉션뷰를 스크롤해서 마지막 셀에 도달하면 그 다음 데이터를 불러와 보여주도록 함 ✅ 목표컬렉션뷰에서 마지막 셀 근처까지 스크롤했을 때만 다음 페이지를 요청하고 싶다.예: 마지막 셀에서 1~2개 남았을 때 미리 로딩.extension CategoryViewController: UICollectionViewDelegate { func collectionView(_ collectionView: UICollectionView, willDisplay cell: UICollectionViewCell, forItemAt indexPath: IndexPath) { let itemCount = categoriesViewModel.eateryFromCategory.count .. 2025. 5. 22. 🔨 화면 UI을 동시에 나오게 해서 사용자 친화적으로 해보기 ❌ 각 UI 가 동시에 나오지 않음 -> 보기 불편함... 🎯 문제 요약섹션 헤더 -> 즉시 표시죔 -> 하드코딩되어 있기 때문 음식점 리스트 -> 비동기 API 호출 후 표시 -> fetchEateries() 가 완료되어야 표시됨다른 데이터 (예: 카테고리) -> 또 다른 ViewModel에서 별도 로딩 -> 동시에 로딩 중이지만, 완료 타이밍이 다름 ✅ 사용자 경험 개선 목표 모든 필요한 데이터가 준비된 후 한 번에 UI를 표시하고 싶음 → "플래시 화면 없이 완전한 콘텐츠"중간에 뜨는 일부 UI 요소 제거 → UI의 일관성과 신뢰감 유지 🛠 해결 전략 제안✅ @Published var isLoading: Bool = true 사용 EateryViewModel, CategoryViewMode.. 2025. 5. 19. 🤔 MVVM 패턴에서 2개 이상의 값의 변화를 감지해야하는 경우에는?(CombineLatest) https://developer.apple.com/documentation/combine/just/combinelatest(_:) combineLatest(_:) | Apple Developer DocumentationSubscribes to an additional publisher and publishes a tuple upon receiving output from either publisher.developer.apple.com ✅ combineLatest(_:)란?combineLatest는 두 개 이상의 Publisher가 내보내는 최신 값을 묶어서 하나로 전달해주는 Combine의 연산자야. 🧠 개념 먼저 이해해보기let publisherA = Just("🍎")let publisherB =.. 2025. 5. 15. 🤔 고차함수를 통해 외부에서 받아온 데이터에 문구를 추가하는 방법 ✅ 현재 화면에서 보이는 카테고리 부분에 추가 문구를 담는 방법 API를 통해 카테고리를 정보를 받아옴 📋 카테고리 목록:- 한식- 서양식- 일식- 중식- 이색음식점- 카페/전통찻집- 클럽 위의 문구에 App Store에서 처럼 이모지를 추가하여 UI 구현하려고 함 ✅ 해결 방법 원본 카테고리에 추가로 이모지를 합친 새로운 배열 생성 📍 "이모지"와 "카테고리" 담을 데이터 모델 생성/// 이모지를 폼할할 새 모델struct CategoryEmogi: Hashable { let id = UUID() let name: String let icon: String var displayName: String { return "\(icon) \(name)" }.. 2025. 5. 15. 🤔 MVVM 패턴에서 앱 실행 시 자동으로 데이터 가져오는 함수를 꼭 viewDidLoad()에서 호출해야 하나? ✅ 현재 구조 분석Task { await eateriesViewModel.fetchEateries()} fetchEateries()를 호출하지 않으면 @Published var eateries는 아무 데이터도 없고, Combine 구독도 반응하지 않음 → UI 업데이트도 안 됨따라서 데이터 fetch는 반드시 필요한 동작이고, UIKit에서는 보통 viewDidLoad() 또는 viewWillAppear()에서 호출하는 게 일반적입니다. ✅ "꼭 viewDidLoad에서만 해야 하나요?"에 대한 답꼭 viewDidLoad()에서 할 필요는 없습니다.하지만 UIKit에서 앱이 시작될 때 ViewController가 메모리에 올라오고 초기화되는 시점은 viewDidLoad()입니다.따라서 “처음 한 번.. 2025. 5. 14. 🔨 API 호출 함수 손 보기 (에러 처리 과정 적용) ✅ 에러 처리 미 포함 func getStoreCategories() async throws -> [StoreCategory] { var components = URLComponents(string: "\(Constants.baseURLString)/categoryCode1") components?.queryItems = [ URLQueryItem(name: "serviceKey", value: Constants.api_key), URLQueryItem(name: "numOfRows", value: "10"), URLQueryItem(name: "pageNo", value: "1"), URLQueryItem(name: "MobileOS", va.. 2025. 4. 25. 📍tour api를 통해 데이터 가져오기 (데이터를 확인할 목적) ✅ 구현하고자 하는 기능 상단에 가로 스크롤 카테고리 컬렉션뷰 (ex: 전체, 한식, 중식, 양식 등).사용자가 카테고리 버튼을 누르면 아래에 관련된 결과를 보여주는 컬렉션뷰가 갱신됨.데이터를 API로부터 가져오는 구조임.이때,StoreCategory (상단 버튼들)는 앱 시작 시 1회 불러오면 되고버튼 클릭 시 해당 카테고리에 맞는 다른 데이터를 불러와야 함 이때 외부 API를 요청하는 방식은 await / async를 사용할 예정 -> 관리 용이성 확보차원 func getStoreCategories() async throws -> [StoreCategory] { // 카테고리 URL 구성 let urlString = "\(Constants.baseURLString)/cat.. 2025. 4. 24. 이전 1 다음 728x90 LIST