73: BucketList, part 6

그루두·2024년 7월 22일
0

100 days of SwiftUI

목록 보기
81/108

Project 14, part 6

challenge

  1. Allow the user to switch map modes, between the standard mode and hybrid.
  2. Our app silently fails when errors occur during biometric authentication, so add code to show those errors in an alert.
  3. Create another view model, this time for EditView. What you put in the view model is down to you, but I would recommend leaving dismiss and onSave in the view itself – the former uses the environment, which can only be read by the view, and the latter doesn’t really add anything when moved into the model.

Tip: That last challenge will require you to make a State instance in your EditView initializer – remember to use an underscore with the property name!

solution

1. 사용자가 맵의 스타일을 변경할 수 있도록 하기

State 변수인 isStandardMap을 만들어 버튼을 클릭하면 hybrid 혹은 standard 모드로 변할 수 있게 설정했다.

                VStack {
                    Spacer()
                    Button(isStandardMap ? "Change to hybrid" :  "Change to standard") {
                        isStandardMap.toggle()
                    }
                    .padding()
                    .background(.white)
                    .clipShape(.capsule)
                    .buttonStyle(.plain)
                }

깃헙 링크

2. face id의 에러에 대한 alert 설정하기


alert의 isPresented에 사용할 변수 isShowingAlert와 alert을 설정해서 face id를 사용할 수 없는 경우에 알림창을 띄웠다.

            Button("Unlock places") {
                viewModel.authenticate()
            }
            .buttonStyle(.borderedProminent)
            .alert("Unable to use biometircs", isPresented: $viewModel.isShowingAlert) {
                Button("Okay", role: .cancel) { }
            } message: {
                Text("Please check your settings.")
            }

깃헙 링크

3. EditView의 ViewModel 만들기

dismiss, onSave를 제외하고 모두 viewModel에서 변수와 함수를 설정하고 EditPlaceView에서는 viewModel로 모두 활용했다.

extension EditPlaceView {
    enum LoadingState {
        case loading, loaded, failed
    }
    @Observable
    class ViewModel {
        var location: Location
        var name: String
        var loadingState = LoadingState.loading
        var pages = [Page]()
        
        init(location: Location, name: String) {
            self.location = location
            self.name = location.name
        }
        
        func createNewLocation() -> Location {
            var newLocation = self.location
            newLocation.id = UUID()
            newLocation.name = self.name
            return newLocation
        }
        
        func fetchNearbyPlaces() async {
            let urlString = "https://en.wikipedia.org/w/api.php?ggscoord=\(self.location.latitude)%7C\(self.location.longitude)&action=query&prop=coordinates%7Cpageimages%7Cpageterms&colimit=50&piprop=thumbnail&pithumbsize=500&pilimit=50&wbptterms=description&generator=geosearch&ggsradius=10000&ggslimit=50&format=json"
            guard let url = URL(string: urlString) else {
                print("Wrong url: \(urlString)")
                return
            }
            do {
                let (data, _) = try await URLSession.shared.data(from: url)
                let decoded = try JSONDecoder().decode(Result.self, from: data)
                self.pages = decoded.query.pages.values.sorted()
                self.loadingState = .loaded
            } catch {
                self.loadingState = .failed
            }
        }
    }
}

깃헙 링크

profile
계속 해보자

0개의 댓글

관련 채용 정보