jacobko
@jacobko
Students
815
Reviews
45
Course Rating
5.0
์์ ํ์ ํ ์ธ์ค
๊ฐ์ ๊ธ์ก์ด ๋ถ๋ด๋๋ ํ์๋ถ๋ค์ ์ํด์ ๋ณธ์ธ ํ๊ต ๋ฉ์ผ ๊ณ์ ์ผ๋ก ์) @***.ac.kr , @***.edu
์ด๋ฉ์ผ ๋ณด๋ด์ฃผ์๋ฉด ์ ๊ฐ์ ํ ์ธ ์ฟ ํฐ (50%) ๋ณด๋ด ๋๋ฆฝ๋๋ค.
๐jacobko@kakao.com
์๋ ํ์ธ์. ๐
SwiftUI ์ ํตํด ๋๊ตฌ๋ ์ฝ๊ฒ iOS APP ์ ๋ง๋ค์ ์๋๋ก ๋ค์ํ ๊ฐ์๋ฅผ ์ ์์ค์ ์์ต๋๋ค.
SwiftUI ๋ฟ๋ง ์๋๋ผ ๋ค์ํ iOS ๊ฐ๋ฐ ๊ด๋ จ ์๋ฃ๋ค์ ์ ์ Jacob's DevLog ์์ ๋ง๋์ค ์ ์์ต๋๋ค.
๐ Jacob's DevLog ๋ฐ๋ก๊ฐ๊ธฐ
Hello. ๐
I'm currently working on creating various tutorials to make it easy for anyone to develop iOS apps through SwiftUI.
You can find not only SwiftUI but also various iOS development-related materials on my Jacob's DevLog.
Courses
Reviews
- [Lv.2] SwiftUI Intermediate - Completing an App with Core Data and SwiftData
- [Lv.3] Practical Network Communication - SwiftUI Combine, Async/Await
- [Lv.1] iOS 17 App Development Basics - Getting Started with SwiftUI
- [Lv.3] Practical Network Communication - SwiftUI Combine, Async/Await
- [Lv.3] Practical Network Communication - SwiftUI Combine, Async/Await
Posts
Q&A
index์ indexSet
Index์ IndexSet ์ฐจ์ด์ ์ค๋ช ์๋ ํ์ธ์ ์ต์ํ๋, index์ IndexSet์ ์ฐจ์ด์ ์ ๋ํด ์ค๋ช ํด๋๋ฆด๊ฒ์.Index vs IndexSet ์ฐจ์ด์ 1. Index (Int ํ์ )// ํ๋์ ์ซ์๋ง ๊ฐ๋ฆฌํด let index = 2 // ๋ฐฐ์ด์ 2๋ฒ์งธ ์์ fruitArray.remove(at: index) // ํ๋๋ง ์ญ์ 2. IndexSet// ์ฌ๋ฌ ๊ฐ์ ์ธ๋ฑ์ค๋ฅผ ๋ด์ ์ ์๋ ์งํฉ let indexSet: IndexSet = [0, 2, 4] // 0๋ฒ, 2๋ฒ, 4๋ฒ ์์๋ค fruitArray.remove(atOffsets: indexSet) // ์ฌ๋ฌ ๊ฐ ๋์ ์ญ์ ์ remove(atOffsets:)๋ฅผ ์ฌ์ฉํ๋์?SwiftUI์ List์์ .onDelete๋ฅผ ์ฌ์ฉํ ๋๋ ์ฌ์ฉ์๊ฐ ์ฌ๋ฌ ํ์ ์ ํํด์ ํ ๋ฒ์ ์ญ์ ํ ์ ์๊ธฐ ๋๋ฌธ์ ๋๋ค.List { ForEach(fruitArray, id: \.name) { fruit in Text("\(fruit.name) - \(fruit.count)๊ฐ") } .onDelete(perform: deleteFruit) // ์ฌ๊ธฐ์ IndexSet์ด ์๋์ผ๋ก ์ ๋ฌ๋จ } ์ค์ ๋์ ์์์ฌ์ฉ์๊ฐ ํธ์ง ๋ชจ๋์์:๋ธ๊ธฐ(0๋ฒ), ๋ฐ๋๋(2๋ฒ)๋ฅผ ๋์ ์ ํ โ IndexSet [0, 2]๊ฐ ์ ๋ฌํ ๋ฒ์ ์ฌ๋ฌ ๊ฐ ์ญ์ ๊ฐ๋ฅ์ ๋ฆฌ๊ตฌ๋ถ Index (Int) IndexSet ์ฉ๋ ๋จ์ผ ํญ๋ชฉ ์ญ์ ๋ค์ค ํญ๋ชฉ ์ญ์ ๋ฉ์๋ remove(at:)remove(atOffsets:) ๊ฐ ์์ 2[0, 2, 4]๊ฐ์ฌํฉ๋๋ค์ ์ด์ฝฅ
- 0
- 2
- 26
Q&A
@Published์ ์ฉ๋
์๋ ํ์ธ์ gaeun ๋. @ObservationIgnored + @Published ์ฌ์ฉ ์ด์ ๋ ๋๊ฐ์ ์๋ก ๋ค๋ฅธ ๋ฐ์ํ ์์คํ ์ ํจ๊ป ์ฌ์ฉํ๊ธฐ์ํด์ ํ ์คํธ ์ฉ์ผ๋ก ์ฌ์ฉํ์ต๋๋ค. ๊ฐ๊ฐ์ ์ญํ @Published (Combine)๋ชฉ์ : Combine ์ฐ์ฐ์ ์ฌ์ฉ (.debounce(), .map() ๋ฑ)์ฉ๋: ๋น์ฆ๋์ค ๋ก์ง ์ฒ๋ฆฌ (์ ํจ์ฑ ๊ฒ์ฌ, ๋ฐ์ดํฐ ๋ณํ)@Observable (SwiftUI)๋ชฉ์ : View ์๋ ์ ๋ฐ์ดํธ์ฉ๋: UI ๋ฐ์์ @ObservationIgnored๊ฐ ํ์ํ๊ฐ?@ObservationIgnored @Published var textFieldID: String = "" var idValid: Bool = falseโ @ObservationIgnored ์์ผ๋ฉดtextFieldID ๋ณ๊ฒฝ โ ์ฆ์ View ์ ๋ฐ์ดํธ.debounce()๊ฐ ๋ฌด์๋ฏธํด์ง๋ถํ์ํ ์ค๋ณต ์ ๋ฐ์ดํธ ๋ฐ์โ @ObservationIgnored ์ฌ์ฉํ๋ฉดtextFieldID โ Combine ํ์ดํ๋ผ์ธ๋ง ์คํ์ฒ๋ฆฌ ๊ฒฐ๊ณผ (idValid) โ View ์ ๋ฐ์ดํธํจ์จ์ ์ธ ์ ๋ฐ์ดํธ ์ ์ด์ค์ ๋์ ํ๋ฆ์ฌ์ฉ์ ์ ๋ ฅ โtextFieldID (@Published) โCombine ํ์ดํ๋ผ์ธ(.debounce โ .map โ .sink) โidValid = true/false โView ์๋ ์ ๋ฐ์ดํธ (@Observable)๊ฒฐ๋ก : Combine์ ๊ฐ๋ ฅํ ์ฐ์ฐ์๋ฅผ ํ์ฉํ๋ฉด์, SwiftUI์ ์๋ก์ด @Observable๋ก View๋ฅผ ํจ์จ์ ์ผ๋ก ์ ๋ฐ์ดํธํ๊ธฐ ์ํ ํ์ด๋ธ๋ฆฌ๋ ๋ฐฉ์ ์ ๋๋ค. ๊ฐ์ฌํฉ๋๋คJacob
- 0
- 1
- 24
Q&A
Sorted, Filter, Map - UserViewModel ๋ถ๋ถ ์ค๋ฅ ๋ฐ์
์๋ ํ์ธ์. nonehour ๋์๋ฌ ๋ฐ์ ์์ธํ์ฌ ์ฝ๋์์ ๋ ๊ฐ์ง ์ฃผ์ ๋ฌธ์ ๊ฐ ๋ฐ์ํ๊ณ ์์ต๋๋ค:ObservableObject ํ๋กํ ์ฝ ์ค์ ์คํจ: UserViewModel ํด๋์ค๊ฐ ObservableObject๋ฅผ ์ฑํํ์ง๋ง ํ์ํ ์๊ตฌ์ฌํญ์ ์ถฉ์กฑํ์ง ๋ชปํ๊ณ ์์ต๋๋ค.Combine ํ๋ ์์ํฌ ๋๋ฝ: @Published ํ๋กํผํฐ ๋ํผ์ ๊ด๋ จ๋ ์ด๊ธฐํ์๋ฅผ ์ฐพ์ ์ ์๋ค๋ ์๋ฌ๊ฐ ๋ฐ์ํฉ๋๋ค.ํด๊ฒฐ ๋ฐฉ๋ฒํ์ผ ์๋จ์ import ๊ตฌ๋ฌธ์ ๋ค์๊ณผ ๊ฐ์ด ์์ ํด์ฃผ์ธ์:import SwiftUI import Combine // ์ด ์ค์ ์ถ๊ฐํด์ฃผ์ธ์ ์ ์ด๋ฐ ์ฐจ์ด๊ฐ ๋ฐ์ํ๋๊ฐ์ด๋ฐ ํ์์ด ๋ฐ์ํ๋ ์ด์ ๋ ๊ฐ๋ฐ ํ๊ฒฝ์ ์ฐจ์ด ๋๋ฌธ์ ๋๋ค:Xcode ๋ฒ์ ์ฐจ์ด: ์ต์ Xcode์์๋ SwiftUI๋ฅผ importํ ๋ Combine๋ ํจ๊ป ์๋์ผ๋ก ๊ฐ์ ธ์ค๋ ๊ฒฝ์ฐ๊ฐ ์์ง๋ง, ๊ตฌ๋ฒ์ ์ด๋ ํน์ ์ค์ ์์๋ ๊ทธ๋ ์ง ์์ ์ ์์ต๋๋ค.iOS ๋ฐฐํฌ ํ๊ฒ: ํ๋ก์ ํธ์ iOS ์ต์ ์ง์ ๋ฒ์ ์ ๋ฐ๋ผ ์๋ import ๋์์ด ๋ฌ๋ผ์ง ์ ์์ต๋๋ค.ํ๋ก์ ํธ ์ค์ : ํ๋ก์ ํธ ์์ฑ ๋ฐฉ์์ด๋ ๋น๋ ์ค์ ์ ๋ฐ๋ผ ๋ชจ๋ import ๋ฐฉ์์ด ๋ค๋ฅผ ์ ์์ต๋๋ค.๊ทผ๋ณธ์ ์ธ ์ดํด@Published์ ObservableObject๋ ์ค์ ๋ก Combine ํ๋ ์์ํฌ์ ํต์ฌ ๊ตฌ์ฑ ์์์ ๋๋ค. ๋ฐ๋ผ์ ์ด๋ค์ ์ฌ์ฉํ ๋๋ ๋ช ์์ ์ผ๋ก Combine์ importํ๋ ๊ฒ์ด ๊ฐ์ฅ ์์ ํ๊ณ ๋ช ํํ ๋ฐฉ๋ฒ์ ๋๋ค.๊ฐ์ ์์ ์ ๋ฌ๋ผ์ ์๋ฌ๊ฐ ๋ฐ์๋์ ์ํด ๋๋ฆฝ๋๋ค.๊ฐ์ฌํฉ๋๋ค.Jacob
- 0
- 1
- 59
Q&A
NavigationBarItems Deprecated
์๋ ํ์ธ์ ์ต์ํ ๋. ์ ๊ฐ ์ง๋ฌธ ํ์ธ์ด ๋ฆ์ด์ ๋ต๋ณ์ด ์ด์ ๋๋ฆฝ๋๋ค. .NavigationBarItems ๋ Deprecated ๋์ด์ .toolbar() ์ฌ์ฉํ๊ฒ๋ ๊ถ์ฅ๋๊ณ ์์ต๋๋ค. ์ง๋ฌธ์ฃผ์ ListBasic ๋ถ๋ถ์์ EditButton() ์ ์ฌ์ฉํ๋๋ฐ, ๋ณ๊ฒฝ๋ ์ฝ๋๋ ๋ค์๊ณผ ๊ฐ์ต๋๋ค. // ๊ธฐ์กด ์ฝ๋ .navigationBarItems(leading: EditButton(), trailing: addButton) // ๋ณ๊ฒฝ๋ ์ฝ๋ .toolbar() ์ฌ์ฉ .toolbar { ToolbarItem(placement: .navigationBarLeading) { EditButton() } ToolbarItem(placement: .navigationBarTrailing) { addButton } ๋ค๋ฅธ NavigationBarItems ์ฌ์ฉํ ๊ฐ์ ์์ ๋ค๋ .toolbar{} ๋ฅผ ์ฌ์ฉํ๋ ๋ฐฉ์์ผ๋ก ๋ณ๊ฒฝํ์ฌ ๊ฐ์ ์ ๊ณต ์์ ํ์ผ์ ์ ๋ฐ์ดํธ ํ๋๋ก ํ๊ฒ ์ต๋๋ค.๊ฐ์ฌํฉ๋๋ค์ ์ด์ฝฅ
- 0
- 3
- 51
Q&A
ViewBuilder ๊ฐ์ ๊ด๋ จ ์ง๋ฌธ์ ๋๋ค.
์๋ ํ์ธ์ ducduck ๋. ์ง๋ฌธ ์ฃผ์ ์ ๊ฐ์ฌํฉ๋๋ค.์ ๋ฆฌํ์๋ฉด ์ ๊ฐ ์ค๋ช ํ ๋ถ๋ถ: LocalViewBuilder์ ์ ์ธ๋ ViewType์ ์ฌ์ฉํด์ ์กฐ๊ฑด๋ถ ๋ทฐ๋ฅผ ๋ง๋ค๊ธฐ ์ํด @ViewBuilder๊ฐ ํ์ํ๋ค.์ง๋ฌธ์๋์ด ์ดํดํ์ ๋ถ๋ถ: ๊ฐ ์กฐ๊ฑด์์ ๋ฐํํ๋ ๋ทฐ๋ค์ด ์๋ก ๋ค๋ฅธ ํ์ (Text, VStack, Image)์ด๋ผ์ @ViewBuilder๊ฐ ํ์ํ๋ค.์ค์ ๋ก๋ ๋ ๋ค ์ฐ๊ฒฐ๋ ๊ฐ์ ์ด์ ์ ๋๋ค!ViewType enum์ ์ฌ์ฉํด์ โ ์กฐ๊ฑด๋ถ ๋ถ๊ธฐ๋ฅผ ๋ง๋ค๊ณ โ ๊ฐ ๋ถ๊ธฐ์์ ๋ค๋ฅธ ํ์ ์ ๋ทฐ๋ฅผ ๋ฐํํ๊ธฐ ๋๋ฌธ์ โ @ViewBuilder๊ฐ ํ์์์๋ก @ViewBuilder private var numberPlate: some View { if type == .one { Text("1") } // Text ํ์ else if type == .two { VStack{} } // VStack ํ์ else { Image("3") } // Image ํ์ }SwiftUI์์ some View๋ ๋จ์ผ ํ์ ๋ง ๋ฐํํ ์ ์๋๋ฐ, @ViewBuilder๊ฐ ์ด๋ฐ ๋ค๋ฅธ ํ์ ๋ค์ ํ๋๋ก ํตํฉํด์ฃผ๋ ์ญํ ์ ํฉ๋๋ค.๊ทธ๋ ๊ฒ ๋๋ฌธ์ ViewType ์ ํ์ฉํ ์กฐ๊ฑด๋ถ ๋ทฐ ๊ตฌํ๊ณผ ์๋ก ๋ค๋ฅธ ํ์ ์ฒ๋ฆฌ, ๋ ๋ค @ViewBuilder ๊ฐ ํ์ํ ์ด์ ์ ๋๋ค
- 0
- 1
- 51
Q&A
CoreData Array์ ๋ณํ์ ๋ฐ๋ฅธ SwiftUI View ๋ณํ ์ ์ฉ(with @Observable Macro)
์๋ ํ์ธ์ ycc3819 ๋.์ง๋ฌธํด์ฃผ์ @Observable์ ํ์ฉํ ์ฝ๋์์, ํด๋ฆญ ์ ~๊ฐ View์ ๋ฐ๋ก ๋ฐ์๋์ง ์๊ณ , ์ฑ์ ์ฌ์์ํ๊ฑฐ๋ ์๋ก์ด ๋ฐ์ดํฐ๋ฅผ ์ ๋ ฅํ ๋ ํ ๋ฒ์ ์ ๋ฐ์ดํธ๋๋ ํ์์ ๋ฐ๊ฒฌํ์ต๋๋ค. ์ด ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๊ธฐ ์ํด ์ฌ๋ฌ ์๋๋ฅผ ํด๋ณธ ๊ฒฐ๊ณผ, @State์ @StateObject์ ์ฐจ์ด๋ก ์ธํด Core Data์ View์ ์ํ๊ฐ ์ฆ์ ๋๊ธฐํ๋์ง ์์์์ ์๊ฒ ๋์์ต๋๋ค. 1. Core Data์์ @StateObject๋ฅผ ์ฌ์ฉํ๋ ์ด์ โข Core Data์ ์ํ๋ View๊ฐ ์ฌ์์ฑ๋๋๋ผ๋ ์ ์ง๋์ด์ผ ํฉ๋๋ค. ๋ฐ๋ผ์, @StateObject๋ก ViewModel์ ๊ด๋ฆฌํ๋ ๊ฒ์ด ์ ํฉํฉ๋๋ค.โข @StateObject๋ ViewModel๊ณผ View์ ์๋ช ์ฃผ๊ธฐ๋ฅผ ์ฐ๊ฒฐํ๊ณ , ์ํ๊ฐ ๋ณ๊ฒฝ๋ ๋ View์ ์๋์ผ๋ก ๋ฐ์๋๋๋ก ๋ณด์ฅํฉ๋๋ค. 2. @State์ @StateObject์ ์ ํ ๊ธฐ์คโข @State:โข ๋จ์ ์ํ(๋ฌธ์์ด, ์ ์, ๋ถ์ธ ๋ฑ)๋ฅผ ๊ด๋ฆฌํ ๋ ์ ํฉ.โข View ์ธ๋ถ์์ ์ํ ๊ณต์ ๊ฐ ํ์ํ์ง ์์ ๊ฒฝ์ฐ ์ฌ์ฉ.โข @StateObject:โข Core Data, ๋น๋๊ธฐ ์์ , ViewModel ๋ฑ ๊ฐ์ฒด ๊ธฐ๋ฐ ์ํ ๊ด๋ฆฌ๊ฐ ํ์ํ ๋ ์ ํฉ.โข View์ ViewModel์ ์๋ช ์ฃผ๊ธฐ๋ฅผ ์ฐ๊ฒฐํ๊ณ ์ํ๋ฅผ ์ ์ง. 3. ์ ์ฉ ์์โข Core Data์ ๊ฐ์ ์ธ๋ถ ๋ฐ์ดํฐ๋ฒ ์ด์ค๋ฅผ ๊ด๋ฆฌํ ๋๋ ViewModel์์ Core Data๋ฅผ ์ด๊ธฐํํ๊ณ , @StateObject๋ฅผ ํตํด ViewModel๊ณผ View๋ฅผ ์ฐ๊ฒฐํด์ผ ๋ฐ์ดํฐ๊ฐ ์ฌ์ฌ์ฉ๋๊ณ ์ํ๊ฐ ์ ์ง๋ฉ๋๋ค. ์ ์ญ์ ์ง๋ฌธ์ ํตํด ์๋ก์ด ๊ด์ ์ ๋ฐฐ์ธ ์ ์์๊ณ , ์ฌ๋ฌ ์๋๋ฅผ ํตํด ์ด ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ ์ ์์์ต๋๋ค. ์ง๋ฌธํด์ฃผ์ ์ ๊ฐ์ฌ๋๋ฆฌ๋ฉฐ, ์์ผ๋ก๋ ๊ถ๊ธํ ์ ์ด ์์ผ๋ฉด ์ธ์ ๋ ์ง ์๋ ค์ฃผ์ธ์.๊ฐ์ฌํฉ๋๋ค.Jacobimport SwiftUI import CoreData import Observation @Observable // Observable ์ฌ์ฉ class CoreDataInterViewModel2 { let container: NSPersistentContainer var savedEntities: [Fish] = [] // @Published ์ฌ์ฉ ์ํจ init() { container = NSPersistentContainer(name: "FishContainer") container.loadPersistentStores { (description, error) in if let error = error { print("ERROR LOADING CORE DATA. \(error)") } else { print("SUCCESSFULLY LOADED CORE DATA: \(description)") } } fetchFish() } func fetchFish() { let request = NSFetchRequest(entityName: "Fish") do { savedEntities = try container.viewContext.fetch(request) } catch { print("ERROR FETCHING CORE DATA: \(error)") } } func saveData() { do { try container.viewContext.save() fetchFish() } catch { print("ERROR SAVING CORE DATA: \(error)") } } func addFish(text: String) { let newFish = Fish(context: container.viewContext) newFish.name = text saveData() } func deleteFish(indexSet: IndexSet) { guard let index = indexSet.first else { return } let entity = savedEntities[index] container.viewContext.delete(entity) saveData() } func updateFish(fish: Fish) { let currentName = fish.name ?? "" fish.name = currentName + "~" saveData() } } // MARK: - VIEW struct CoreDataInter2: View { @State private var textFieldText: String = "" @StateObject var vm: CoreDataInterViewModel = .init() // ๊ธฐ์กด @StateObject ๋ฅผ ์ฌ์ฉ var body: some View { NavigationStack { VStack(spacing: 20) { TextField("์๋ก์ด ์์ ์ ์ ๋ ฅํ์ธ์", text: $textFieldText) .textFieldStyle(.roundedBorder) Button { guard !textFieldText.isEmpty else { return } vm.addFish(text: textFieldText) textFieldText = "" } label: { Text("์ถ๊ฐํ๊ธฐ") .padding() .background(Color.blue) .foregroundColor(.white) .cornerRadius(8) } List { ForEach(vm.savedEntities, id: \.self) { fish in Text(fish.name ?? "์ด๋ฆ ์์") .onTapGesture { vm.updateFish(fish: fish) } } .onDelete { indexSet in vm.deleteFish(indexSet: indexSet) } } .listStyle(.plain) } .padding() .navigationTitle("Fish Market") } } } #Preview { CoreDataInter2() }
- 0
- 2
- 159
Q&A
Xcode version ๋ฌธ์
์๋ ํ์ธ์ miso lim ๋.์ ๊ณต๋ ๊ฐ์ code ํ์ผ์ xcode 16.2 ๋ฒ์ (iOS 18) ์์ ์คํํด๋ณด๋ ์ด์ ์์ด ์ ๋์์ต๋๋ค.ํน์ ๊ฐ์ ์ค๊ฐ๋ง๋ค ์๋ฌ๊ฐ ๋ฐ์ ๋๋ฉด ์ธ์ ๋ ์ง ์ง๋ฌธ ์ฃผ์๋ฉด ๋ฒ์ ์ ๋ง์ถฐ์ ์์ ๋ ์ฝ๋๋ก ๋ต๋ณํด ๋๋ฆฌ๊ฒ ์ต๋๋ค.๊ฐ์ฌํฉ๋๋คJacob
- 0
- 2
- 145
Q&A
init-deinit์ ๋ฌดํ๋ฃจํ์ ๋ฒ์ด๋๋ ๋ฐฉ๋ฒ์ด ๊ถ๊ธํฉ๋๋ค.
์๋ ํ์ธ์ ycc3819 ๋.์ ๋ ํ์ธํ ๊ฒฐ๊ณผ @Observable ๋ก ๋ณ๊ฒฝํ ์ ๋ฌดํ ๋ฃจํ์ด ๋ฐ์๋๋๊ฒ์ ํ์ธํ์์ต๋๋ค.๋ฐ์ํ ์์ธ์ ๋ณด์๋ฉด..1. ๋ฌดํ ๋ฃจํ ๋ฐ์ ์์ธโข @State๋ ๊ฐ ํ์ ์ํ๋ฅผ ๊ด๋ฆฌํ๊ธฐ ์ํด ์ค๊ณ๋์์ต๋๋ค. ํ์ง๋ง @Observable์ ํด๋์ค ํ์ (์ฐธ์กฐ ํ์ )์ ๊ธฐ๋ฐ์ผ๋ก ๋์ํ๋ฉฐ, SwiftUI๊ฐ ์ํ ๋ณ๊ฒฝ์ ๊ฐ์งํ ๋ ViewModel์ด ๋ฐ๋ณต์ ์ผ๋ก ์ด๊ธฐํ๋๋ ๋ฌธ์ ๊ฐ ๋ฐ์ํฉ๋๋ค.โข ์ด๋ก ์ธํด init๊ณผ deinit์ด ๋ฌดํํ ํธ์ถ๋๋ฉฐ ๋ฃจํ์ด ๋ฐ์ํฉ๋๋ค.2. ๊ทธ๋์ ๊ฐ์ ์ฝ๋ ์ฒ๋ผ @StateObject๋ฅผ ์ฌ์ฉํด์ผ ํ๋ ์ด์ โข ๊ธฐ์กด ๊ฐ์ ์ฝ๋์์ @StateObject๋ ObservableObject์ ํจ๊ป ์ฌ์ฉ๋๋ฉฐ, SwiftUI ๋ทฐ์ ์๋ช ์ฃผ๊ธฐ์ ViewModel์ ์ด๊ธฐํ/ํด์ ๋ฅผ ์์ ์ ์ผ๋ก ๊ด๋ฆฌํฉ๋๋ค.โข @StateObject๋ ๋ทฐ๊ฐ ๋ค์ ๋ ๋๋ง๋๋๋ผ๋ ViewModel์ ์ฌ์ฌ์ฉํ๊ธฐ ๋๋ฌธ์ ๋ฌดํ ๋ฃจํ ๋ฌธ์ ๊ฐ ๋ฐ์ํ์ง ์์ต๋๋ค.๊ทธ๋์ ๊ฐ์ ๋ด์ฉ ์ฝ๋๋ฅผ @Observable ๋ก ๋ฐ๊ฟ๋๋ ๊ฐ์์์ ๋ค๋ฃจ์ง ์์ .onAppear, .onDisappear ๋ฅผ ์ฌ์ฉํด์ Weak self ์ฝํ ์ฐธ์กฐ ๋ด์ฉ์ ํ์ธ ํ์ค ์ ์์ต๋๋ค. (@State, ์ init, deinit ์ ์ฌ์ฉํ๊ฒ ๋๋ฉด ๋ผ์ดํ ์ฌ์ดํด ์ถฉ๋๋ก ์ธํด ๋ฌดํ ๋ฃจํ์ด ๋๊ธฐ ๋๋ฌธ์ ๋๋ค. )์์ ์ฝ๋import SwiftUI import Observation // @Observable ์ฌ์ฉ์ ์ํด ์ํฌํธ // MARK: - VIEWMODEL @Observable class WeakSelfInterViewModel { var data: String? = nil // ๋ฐ์ดํฐ๋ฅผ ๊ด๋ฆฌํ๋ ์ํ ๋ณ์ init() { getData() // ์ด๊ธฐ ๋ฐ์ดํฐ ๋ก๋ } func getData() { // ๋น๋๊ธฐ๋ก ๋ฐ์ดํฐ๋ฅผ ๋ก๋ํ๋ฉฐ, ๊ฐํ ์ฐธ์กฐ ์ํ์ ๋ฐฉ์งํ๊ธฐ ์ํด [weak self] ์ฌ์ฉ DispatchQueue.main.asyncAfter(deadline: .now() + 10) { [weak self] in self?.data = "NEW DATA!" // ๋ฐ์ดํฐ ์ ๋ฐ์ดํธ } } } // MARK: - SCREEN 1 struct WeakSelfInter: View { var body: some View { NavigationStack { // 2๋ฒ ํ์ด์ง๋ก ์ด๋ํ๋ฉฐ ViewModel์ 2๋ฒ ํ์ด์ง์์๋ง ์์ฑ ๋ฐ ๊ด๋ฆฌ NavigationLink("2๋ฒ์งธ ํ์ด์ง๋ก ์ด๋") { WeakSelfInter2() } .navigationTitle("1๋ฒ์งธ ํ์ด์ง") // ๋ค๋น๊ฒ์ด์ ํ์ดํ ์ค์ } } } // MARK: - SCREEN 2 struct WeakSelfInter2: View { @State private var vm = WeakSelfInterViewModel() // @State๋ก ViewModel ๊ด๋ฆฌ var body: some View { VStack { Text("2๋ฒ์งธ ํ์ด์ง") .font(.largeTitle) .foregroundColor(.red) // ViewModel์ ๋ฐ์ดํฐ๊ฐ ์์ผ๋ฉด ํ์ if let data = vm.data { Text(data) } } .onAppear { // ๋ทฐ๊ฐ ๋ํ๋ ๋ ๋ฐ์ดํฐ ๋ก๋ ํ์ธ print("๋ทฐ๊ฐ ๋ํ๋จ") } .onDisappear { // ๋ทฐ๊ฐ ์ฌ๋ผ์ง ๋ ๋ก๊ทธ ์ถ๋ ฅ print("๋ทฐ๊ฐ ์ฌ๋ผ์ง") // ViewModel์ @State๋ก ๊ด๋ฆฌ๋๋ฏ๋ก ์๋์ผ๋ก ๋ฉ๋ชจ๋ฆฌ์์ ํด์ ๋จ } } } // MARK: - PREVIEW #Preview { WeakSelfInter() // ๋ฏธ๋ฆฌ๋ณด๊ธฐ์์ WeakSelfInter ํ๋ฉด ํ์ธ }
- 1
- 2
- 129
Q&A
Apple ๊ณต์ ๋ฌธ์ ๋ณด๋๋ฒ
์๋ ํ์ธ์ ์ด์ฌ์ ๋.์ ํ ๊ณต์๋ฌธ์ ์กฐํ ํ๋ ๊ฒ์ ๋ํด์ ๋ช๊ฐ์ง ์ ์ ํ์ ๋๋ฆฌ์๋ฉด https://developer.apple.com/documentation/์ ํ ๋ฌธ์๋ ์ฃผ์ ๋ณ๋ก ์ ์ ๋ฆฌ๋์ด ์์ง๋ง, ํน์ ๊ธฐ๋ฅ์ ๋ฐ๋ก ์ฐพ๊ธฐ ์ํด์๋ ๋จผ์ ๊ฐ๋ ํ์ ์ด ์ค์ํฉ๋๋ค. ์๋ฅผ ๋ค์ด, SwiftUI์์ ๋ทฐ๋ฅผ ๋ค๋ฃฌ๋ค๋ฉด โView Protocolโ๋ก ๊ฒ์์ ์์ํ๋ ๊ฒ์ด ์ ์ฉํฉ๋๋ค. ํค์๋ ๊ฐ๊ฒฐํ: ๋ฌธ์ ๊ฒ์์ ๊ตฌ์ฒด์ ์ธ ์ฉ์ด๋ฅผ ๊ฐ๋จํ๊ฒ ์ ๋ ฅํ ์๋ก ์ ํํ ๊ฒฐ๊ณผ๋ฅผ ์ป์ ์ ์์ต๋๋ค. ์๋ฅผ ๋ค์ด โSwiftUI delete text items in loopโ๋ณด๋ค๋ โSwiftUI List deleteโ์ฒ๋ผ ํต์ฌ ๋จ์ด๋ก ์ค์ฌ์ ๊ฒ์ํด๋ณด์ธ์.๋ฉ์๋ ์ด๋ฆ, ํ๋กํ ์ฝ ์ฌ์ฉ: Swift๋ SwiftUI์์ ์ ๊ณตํ๋ ๋ฉ์๋๋ ํ๋กํ ์ฝ ์ด๋ฆ์ ์ง์ ๊ฒ์ํ๋ฉด ์ ์ฉํฉ๋๋ค. ์๋ฅผ ๋ค์ด, โForEachโ๋ฅผ ์ด์ฉํ ๋ฐ๋ณต ์ฒ๋ฆฌ๋ฅผ ๋ฌธ์์์ ์ฐพ์๋ณด๊ณ , ๊ทธ ์์๋ฅผ ํตํด ๊ตฌํ ๋ฐฉ๋ฒ์ ์ดํดํ ์ ์์ต๋๋ค.์๋ฅผ ๋ค์ด, ๋ฐ๋ณต๋ฌธ์ ํตํด ํ ์คํธ๋ฅผ ํ ๋ฒ์ ์ง์ฐ๋ ๊ธฐ๋ฅ์ ์ฐพ๊ณ ์ ํ๋ค๋ฉด:โข ๋จผ์ โSwiftUI ForEachโ๋ฅผ ๊ฒ์ํฉ๋๋ค. ์ด ๋ฐ๋ณต๋ฌธ ๊ตฌ์กฐ์ ๋ํ ๋ฌธ์๋ฅผ ์ฐพ๊ณ , ForEach ๋ด๋ถ์์ ๋ฐ์ดํฐ๋ฅผ ์ฒ๋ฆฌํ๋ ๋ฐฉ๋ฒ์ ์ดํดํ ์ ์์ต๋๋ค.โข ๊ทธ๋ค์์ผ๋ก โSwiftUI delete itemsโ๋ โSwiftUI onDeleteโ์ ๊ฐ์ ํค์๋๋ก ๊ฒ์ํฉ๋๋ค. SwiftUI์ List์์ ํญ๋ชฉ์ ์ญ์ ํ๋ ๊ธฐ๋ฅ์ ์ฃผ๋ก onDelete() ๋ฉ์๋๋ก ์ฒ๋ฆฌํฉ๋๋ค.โข ์ด๋ ๊ด๋ จ ๋ฌธ์๋ฅผ ์ฐพ์ผ๋ฉด, ๋ค์ํ ์์ ์ ํจ๊ป ์ฌ์ฉ๋ฒ์ ๋ฐฐ์ธ ์ ์์ต๋๋ค. ์๋ฅผ ๋ค์ด, ForEach์ onDelete()๋ฅผ ๊ฒฐํฉํ๋ฉด ๋ฆฌ์คํธ์ ์ฌ๋ฌ ํ ์คํธ ํญ๋ชฉ์ ๋ฐ๋ณต์ ์ผ๋ก ์ญ์ ํ๋ ๊ธฐ๋ฅ์ ๊ตฌํํ ์ ์์ต๋๋ค.SwiftData ๊ฐ์ ๋ถ๋ถ์ ์ค๋์ด๋ ๋ด์ผ ์ค์ผ๋ก ์ ๋ฐ์ดํธ ์์ ์ ๋๋ค.๊ฐ์ฌํฉ๋๋ค.Jacob
- 0
- 2
- 257
Q&A
5์ ์ ๋ฐ์ดํธ ์์ ์ด์๋ , iOS17 ์ปจํ ์ธ SwifData ์ ๋ฐ์ดํธ ์ธ์ ๋๋์ ?
์๋ ํ์ธ์ ๋ํ๋.์ ๊ฐ ๊ฐ์ธ์ ์ธ ์ฌ์ ์ผ๋ก์ธํด์ ์ ๋ฐ์ดํธ๊ฐ ์ง์ฐ๋๊ณ ์์ต๋๋ค. 7์ ์ค์ผ๋ก ์ต๋ํ ๋นจ๋ฆฌ SwiftData ๋ถ๋ถ ๊ฐ์ ์ ๋ก๋ ํ๊ฒ ์ต๋๋ค. ์ํด ๋ถํ๋๋ฆฝ๋๋ค. ๊ฐ์ฌํฉ๋๋ค.
- 0
- 1
- 231





![Thumbnail image of the [Lv.2] SwiftUI Intermediate - Completing an App with Core Data and SwiftData](https://cdn.inflearn.com/public/courses/331891/cover/3e85efeb-7057-485e-ab5b-8a600150fc5a/331891.png?w=148)
![Thumbnail image of the [Lv.3] Practical Network Communication - SwiftUI Combine, Async/Await](https://cdn.inflearn.com/public/courses/335552/cover/3830b158-b7f4-4042-9081-8fb1dc87881d/335552.png?w=148)
![Thumbnail image of the [Lv.1] iOS 17 App Development Basics - Getting Started with SwiftUI](https://cdn.inflearn.com/public/courses/329815/cover/f0cadfc4-389a-4cef-a67b-72fed66ff4c5/Basic_Cover.png?w=148)