IOS17로 업데이트 됨에 따라, @Observable 매크로를 활용하여 ViewModel을 활용하면, 상태 변화를 감지하여 'View에서 자동적으로 업데이트 된다.'라고 알고 있습니다. @Observable 매크로를 사용해서 코드를 업데이트하던 중 궁금증이 생겨 질문을 남겨봅니다. ContentView, VideoView에서 AnimalViewModel의 인스턴스를 갖고 있을 때, var로 정의했을 때와 let으로 정의를 했을 때의 차이점이 있을까요? struct ContentView: View { // let이나 var이나 상관없는가? let vm: AnimalViewModel var body: some View { NavigationStack{ List{ // 1. Cover Image - hero Image CoverImageView(vm: vm) 관련내용을 공부하다보니, 해당 링크에서 https://www.donnywals.com/comparing-observable-to-observableobjects/ " Defining an @Observable as a let property" 부분에 HomeView에서 ViewModel에 @State 프로퍼티 래퍼를 사용한 후 let을 사용한다? 라는 내용을 본적이 있습니다. GalleryView에서 @State 프로퍼티 래퍼와 @Bindable 프로퍼티 래퍼를 사용했을 때의 차이점이 뭘까요 ㅠㅠ . 우선, @State로 했을 때는 변화의 감지를 HomeView에서도 GalleryView에서도 잘 작동하여, 슬라이더를 변화시켰을 때 Grid의 개수가 바뀝니다. 하지만 @Bindable 프로퍼티 래퍼를 사용했을 때에는 GalleryView에서만 슬라이더 변화를 감지 하고, HomeView에서는 변화를 감지하지 못하는 상황이 벌어집니다. @State var vm: AnimalViewModel @Bindable var vm: AnimalViewModel struct GallaryView: View { @State var vm: AnimalViewModel var body: some View { NavigationStack{ ScrollView(.vertical, showsIndicators: false){ VStack(spacing: 30){ // 1. Image Image(vm.selectedAnimal) .resizable() .scaledToFill() .frame(width: 250, height: 250) .clipShape(Circle()) .overlay(Circle().stroke(Color.accentColor, lineWidth: 5)) // 2. Slider Slider(value: $vm.gridColumn, in: 2...4, step: 1) .padding(0) .onChange(of: vm.gridColumn) { withAnimation(Animation.easeInOut(duration: 1.0)){ vm.gridSwitch() } } // 3. Grid LazyVGrid(columns: vm.gridLayout, spacing: 20){ ForEach(vm.animals){ animal in Image(animal.image) .resizable() .scaledToFill() .frame(width: 80, height: 80) .clipShape(Circle()) .overlay(Circle().stroke(Color.white, lineWidth: 1)) .onTapGesture { withAnimation(Animation.spring()){ vm.selectedAnimal = animal.image } } } } } //:VSTACK .padding() } //:SCROLL .navigationTitle("갤러리") .navigationBarTitleDisplayMode(.inline) } //:NAVIGATION } } 추가로, @Observable 매크로를 이용한 예시가 잘 정리되어 있는 문서들이 있을까요?? 제가 잘 이해를 못한 건지, 이 부분이 너무 어렵네요. 감사합니다 😀
"ProfileView(viewModel: ProfileViewModel(user: user))" ProfileView에는 init함수가 존재하지 않지만 viewModel을 인자로 받아서 생성자를 호출할 수 있는 이유가 무엇인지 궁금합니다. viewModel에 @state를 사용했기 때문일까요? "구조체에 @state변수가 있다면 해당 구조체를 새로 만들 때 인자로 부여할 수 있다." 이렇게 이해하면 될까요?? @state에 대해 설명부탁드립니다
NewPostViewModel.swift 파일에서 @Observable에 Unknown attribute 'Observable' 이런 오류가 발생합니다... 찾아보니 ios버전이 17이하버전에서는 Observable을 사용할 수 없다고하는데, 제가 지금 16.4버전을 사용중에 있습니다. 버전을 업그레이드하려는데, 이 부분도 해결이 되지 않아서 그러는데, 어떻게 해야할까요?
끝말잇기 앱을 만들다가 궁금증이 생겼습니다. textfield 로 입력 받은 문자열을 수정해서 사용하고 싶을 때 (예: 사용자가 소문자로 입력한 영문자를 모두 대문자로 바꾸고 싶을 때) 어떻게 할 수 있나요? 입력받은 값을 저장한 변수를 건드리면 에러가 뜹니다. 즉, nextWord = nextWord + "수정 더함" 해도 에러가 나고 다른 변수에 대입한 후 그 변수를 바꾸려 해도 (nextWord2 = nextWord + "수정") 에러가 납니다.
안녕하세요 강의 너무 잘 듣고 있습니다 ! 예전에 앱 만들다가 궁금했던 것이 두가지 정도 있어 여쭤보려고 합니다. 페이지 페이지 가 연결되는 느낌이 아니라 아예 다른 페이지로 넘어가고 싶은데, Tab, NavigationLink 말고 다른 방법이 있을까요? 보통 이럴 때는 그냥 NavigationLink 로 이동시키고 hidden을 false를 주는건가요? 그리고 페이지 내 컴포넌트 안에 있는 컴포넌트에서 버튼을 눌렀을 때 Sheet이 올라오게 하고 싶은데 그럴 때 Sheet의 전체 크기가 전체 화면 기준이 아니라 그 컴포넌트가 기준이 되어 작게 나타났을 때가 있었습니다.이런 경우에는 어떻게 해결하나요? 답변해주시면 감사하겠습니다.
struct MatchedGemomatryEffectInter: View { @State private var isToogle: Bool = false var body: some View { VStack { RoundedRectangle(cornerRadius: 20) .frame(width: 100, height: 100) .offset(y: isToogle ? UIScreen.main.bounds.height * 0.7 : 0) Spacer() } .frame(maxWidth: .infinity,maxHeight: .infinity) .background(.green) .onTapGesture { withAnimation(.spring()) { isToogle.toggle() } } } } 안녕하세요. 동일하게 작성했는데 저는 상하 safeArea 가 채워진체 나옵니다. 타겟은 iOS15 입니다. 강의 관련된 질문은 언제나 환영입니다 😄 코드 관련 상세하게 작성해주시면 더 좋아요! (상세코드를 붙여넣기 해주세요) 마크다운을 사용해서 편리하게 글을 작성하세요 먼저 유사한 질문이 있었는지 먼저 검색 해보는 습관~ 인프런 서비스 운영 관련 문의는 1:1 문의하기를 이용해주세요
예제를 전부 구현한 상태에서 아래 코드를 통해서 뱃지 숫자를 1씩 올려서 보내게 되어 있습니다. func scheduleNotification() { //notification 내용 설정 let content = UNMutableNotificationContent() content.title = "Local Notification 테스트 1" content.subtitle = "앱 알람 테스트 중입니다." content.sound = .default content.badge = NSNumber(value: UIApplication.shared.applicationIconBadgeNumber + 1) 하지만 아래 코드에 의해 뱃지가 0 으로 리셋되기에 항상 1만 발송하게 됩니다. .onChange(of: scenePhase) { newValue in if newValue == .active { UIApplication.shared.applicationIconBadgeNumber = 0 } } 추가적으로 5초 딜레이로 설정후 로컬노티 여러번 누른후에 앱을 종료하고 기다리면 노티가 여러개 오지만 모두 뱃지 1로 오기 때문에 앱아이콘에 뱃지는 1로 계속 옵니다. 실무에서 로컬노티에 카운터를 현재 뱃지 카운터에 + 1 해서 보내는건 실효성이 없어보이는데요. 따로 해결할 방법이 있을까요 ? 조언 부탁드립니다. 강의 관련된 질문은 언제나 환영입니다 😄 코드 관련 상세하게 작성해주시면 더 좋아요! (상세코드를 붙여넣기 해주세요) 마크다운을 사용해서 편리하게 글을 작성하세요 먼저 유사한 질문이 있었는지 먼저 검색 해보는 습관~ 인프런 서비스 운영 관련 문의는 1:1 문의하기를 이용해주세요
17:29 부분에서 변수명 scenePhase 타이핑중 sce 까지만 타이핑 하고 바로 화면 이동 됩니다. 컷 편집 잘못된거 같아요. 강의 관련된 질문은 언제나 환영입니다 😄 코드 관련 상세하게 작성해주시면 더 좋아요! (상세코드를 붙여넣기 해주세요) 마크다운을 사용해서 편리하게 글을 작성하세요 먼저 유사한 질문이 있었는지 먼저 검색 해보는 습관~ 인프런 서비스 운영 관련 문의는 1:1 문의하기를 이용해주세요
강의 중 함수내 코드폴딩 단축키는 커맨드 + 옵션 + 왼쪽 방향키 입니다. Sorted,Filter,Map 강의 8:14 에 커맨드 + 쉬프트 + 왼쪽 방향키로 설명 되어 있어서 있어서 혼동 했네요. 강의 관련된 질문은 언제나 환영입니다 😄 코드 관련 상세하게 작성해주시면 더 좋아요! (상세코드를 붙여넣기 해주세요) 마크다운을 사용해서 편리하게 글을 작성하세요 먼저 유사한 질문이 있었는지 먼저 검색 해보는 습관~ 인프런 서비스 운영 관련 문의는 1:1 문의하기를 이용해주세요
안녕하세요. .scrollTransition 에서 phase 값을 실시간으로 확인해 보고 싶습니다. swiftUI 에서 print 를 통해 콘솔에 디버깅 하고 싶은데 어떻게 하면 좋을까요 ? 강의 관련된 질문은 언제나 환영입니다 😄 코드 관련 상세하게 작성해주시면 더 좋아요! (상세코드를 붙여넣기 해주세요) 마크다운을 사용해서 편리하게 글을 작성하세요 먼저 유사한 질문이 있었는지 먼저 검색 해보는 습관~ 인프런 서비스 운영 관련 문의는 1:1 문의하기를 이용해주세요
안녕하세요. 이전 문의에 대한 답변 잘 확인했습니다. 답변 감사합니다. //GridLayout @Published var gridLayout: [GridItem] = [GridItem(.flexible())] @Published var gridColumn: Double = 4.0 //init init() { gridSwitch() } //func func gridSwitch() { print("gridSwitch") gridLayout = Array(repeating: GridItem(.flexible()), count: Int(gridColumn)) } 방금 실습 프로젝트 진도 마무리하고 grid 쪽 다시 보고 있는데요 gridSwitch() 함수에 print 넣고 체크해 보니 슬라이더 움직이면 위에 함수가 2번씩 호출됩니다. gridLayout 과 gridColumn 2개 값이 @ObservedObject 되어 있어서 각각 변경이 되서 총 2번 호출되는건지요 ? 차후 저런 변수가 많이 들어가 있는 함수는 갯수만큼 호출될꺼 같은데. 어떻게 대응해야 하는지 효율적인 방식이 있는지 조언 부탁드려도 될까요 ? 강의 관련된 질문은 언제나 환영입니다 😄 코드 관련 상세하게 작성해주시면 더 좋아요! (상세코드를 붙여넣기 해주세요) 마크다운을 사용해서 편리하게 글을 작성하세요 먼저 유사한 질문이 있었는지 먼저 검색 해보는 습관~ 인프런 서비스 운영 관련 문의는 1:1 문의하기를 이용해주세요
시뮬레이터나 디바이스에서 YoutubeView 에 로딩된 유튜브화면 플레이버튼 누르면 아래처럼 워닝이 쭉 뜹니다. 어떻게 해결 해야 할까요 ? (영상이 플레이는 되는데, 로그에 저렇게 나오네요) Snapshotting a view (0x106f3acb0, _UIButtonBarStackView) that is not in a visible window requires afterScreenUpdates:YES. https://www.youtube.com/embed/IRRCX1ZQdVY Error acquiring assertion: <Error Domain=RBSServiceErrorDomain Code=1 "(originator doesn't have entitlement com.apple .runningboard.assertions.webkit AND originator doesn't have entitlement com.apple .multitasking.systemappassertions)" UserInfo={NSLocalizedFailureReason=(originator doesn't have entitlement com.apple .runningboard.assertions.webkit AND originator doesn't have entitlement com.apple .multitasking.systemappassertions)}> 0x178060270 - ProcessAssertion::acquireSync Failed to acquire RBS assertion 'WebKit Media Playback' for process with PID=10,676, error: Error Domain=RBSServiceErrorDomain Code=1 "(originator doesn't have entitlement com.apple .runningboard.assertions.webkit AND originator doesn't have entitlement com.apple .multitasking.systemappassertions)" UserInfo={NSLocalizedFailureReason=(originator doesn't have entitlement com.apple .runningboard.assertions.webkit AND originator doesn't have entitlement com.apple .multitasking.systemappassertions)} Error acquiring assertion: <Error Domain=RBSServiceErrorDomain Code=1 "(originator doesn't have entitlement com.apple .runningboard.assertions.webkit AND originator doesn't have entitlement com.apple .multitasking.systemappassertions)" UserInfo={NSLocalizedFailureReason=(originator doesn't have entitlement com.apple .runningboard.assertions.webkit AND originator doesn't have entitlement com.apple .multitasking.systemappassertions)}> 0x1780603b0 - ProcessAssertion::acquireSync Failed to acquire RBS assertion 'WebKit Media Playback' for process with PID=10,512, error: Error Domain=RBSServiceErrorDomain Code=1 "(originator doesn't have entitlement com.apple .runningboard.assertions.webkit AND originator doesn't have entitlement com.apple .multitasking.systemappassertions)" UserInfo={NSLocalizedFailureReason=(originator doesn't have entitlement com.apple .runningboard.assertions.webkit AND originator doesn't have entitlement com.apple .multitasking.systemappassertions)} Error acquiring assertion: <Error Domain=RBSServiceErrorDomain Code=1 "(originator doesn't have entitlement com.apple .runningboard.assertions.webkit AND originator doesn't have entitlement com.apple .multitasking.systemappassertions)" UserInfo={NSLocalizedFailureReason=(originator doesn't have entitlement com.apple .runningboard.assertions.webkit AND originator doesn't have entitlement com.apple .multitasking.systemappassertions)}> 0x178060cc0 - ProcessAssertion::acquireSync Failed to acquire RBS assertion 'WebKit Media Playback' for process with PID=10,678, error: Error Domain=RBSServiceErrorDomain Code=1 "(originator doesn't have entitlement com.apple .runningboard.assertions.webkit AND originator doesn't have entitlement com.apple .multitasking.systemappassertions)" UserInfo={NSLocalizedFailureReason=(originator doesn't have entitlement com.apple .runningboard.assertions.webkit AND originator doesn't have entitlement com.apple .multitasking.systemappassertions)} Visual isTranslatable: NO; reason: observation failure: noObservations Request to remove background on an unsupported device. Error Domain= com.apple .VisionKit.RemoveBackground Code=-8 "(null)" Error generating mask only remove background image for analysis: <VKCImageAnalysisResult: 0x104b69d80> - Error Domain= com.apple .VisionKit.RemoveBackground Code=-8 "(null)" [MADService] Client XPC connection invalidated LaunchServices: disconnect event interruption received for service com.apple.lsd.open 강의 관련된 질문은 언제나 환영입니다 😄 코드 관련 상세하게 작성해주시면 더 좋아요! (상세코드를 붙여넣기 해주세요) 마크다운을 사용해서 편리하게 글을 작성하세요 먼저 유사한 질문이 있었는지 먼저 검색 해보는 습관~ 인프런 서비스 운영 관련 문의는 1:1 문의하기를 이용해주세요
struct ListBasic: View { //property @State var fruits:[String] = [ "사과","오렌지","바나나","수박" ] @State var meats:[String] = [ "소고기","돼지고기","닭고기" ] var body: some View { NavigationView { List { Section { //content ForEach(fruits, id: \.self) { fruit in Text(fruit) .font(.body) .foregroundColor(.white) .padding(.vertical) } .onDelete(perform: delete) .onMove(perform: move) .listRowBackground(Color.blue) } header: { Text("과일종류") .font(.headline) .foregroundColor(.brown) } // : Section Section { ForEach(meats, id: \.self) { meat in Text(meat) .font(.body) } } header: { Text("고기종류") .font(.headline) .foregroundColor(.red) } // : Section }//: List .navigationTitle("우리동네 마트") .navigationBarItems(leading: EditButton(), trailing: addButton) }// : NavigationView } // Fucntion func delete(indexSet: IndexSet) { fruits.remove(atOffsets: indexSet) } func move(indices:IndexSet , newOffSet: Int) { fruits.move(fromOffsets: indices, toOffset: newOffSet) } var addButton: some View { Button { fruits.append("딸기") } label: { Text("Add") } } } 강의 내용에 따라 작성후 프리뷰 플레이에서 확인해 보니 에디트 모드에서 과일을 move 해봤는데 버벅 거리면서 이동하려던 과일이 원래 위치로 돌아갑니다. 증상 분석 프리뷰에서 테스트 프리뷰 플레이에서 move 시 원래 위치로 돌아감 2. 디바이스에서 테스트 move 정상 작동 딸기 추가 시 아래 메시지 노출 ForEach<Array<String>, String, ModifiedContent<Text, _PaddingLayout>>: the ID 딸기 occurs multiple times within the collection, this will give undefined results! CADisplayTimingsControl too many reasons. CADisplayTimingsControl too many reasons. CADisplayTimingsControl too many reasons. 강의 관련된 질문은 언제나 환영입니다 😄 코드 관련 상세하게 작성해주시면 더 좋아요! (상세코드를 붙여넣기 해주세요) 마크다운을 사용해서 편리하게 글을 작성하세요 먼저 유사한 질문이 있었는지 먼저 검색 해보는 습관~ 인프런 서비스 운영 관련 문의는 1:1 문의하기를 이용해주세요
안녕하세요. 먼저 좋은 강의 만들어주셔서 감사합니다. 실제 프로젝트에 SWIFTUI 를 적용하려다보니 커스텀팝업(UIKIT으로는 투명배경 ViewController)를 어떤식으로 적용 할 수 있는건지 잘모르겠습니다. 혹시 사용하고 있는 방법이 있으시면 알려주실 수 있을까요?
강사님, 안녕하세요. 강의를 보면서 코드를 작성하던 중에 코어 데이터에서 값을 입력 할 때에 중복값이 계속 들어가는것을 확인하고 이것을 막고자 합니다. 어떤 방법으로 해야 하는지요? 아니면 제가 강의 중에서 놓친 부분이 있을 수도 있으니 해당 영상의 위치를 알려주시면 살펴보겠습니다. 감사합니다.