스트리밍은 대부분의 브라우저와
Developer 앱에서 사용할 수 있습니다.
-
SwiftData의 새로운 기능
SwiftData는 표현적이며 선언적인 API로 앱의 영속성을 강화할 수 있도록 도와줍니다. 복합적인 고유성 관련 제약 사항, #Index를 통한 더욱 빠른 쿼리, Xcode 미리보기의 쿼리 및 풍부한 서술 표현 등 SwiftData의 개선 사항을 알아보세요. 이러한 기능을 사용하여 더욱 정교한 모델을 표현하고 앱 내 성능을 향상하는 방법을 함께 모색해 봅니다. SwiftData에서 맞춤형 데이터 저장소를 만들거나 History API를 사용하는 방법을 알아보려면 ‘SwiftData로 자체 데이터 저장소 만들기' 또는 ‘SwiftData 기록으로 모델 변경 사항 추적하기'를 시청하세요.
챕터
- 0:00 - Introduction
- 0:57 - Adopt SwiftData
- 2:11 - Customize the schema
- 2:43 - #Unique macro
- 3:37 - History API
- 4:29 - Tailor a model container
- 5:39 - Custom data stores
- 6:41 - Xcode previews
- 9:20 - Customize queries
- 10:18 - #Expression macro
- 11:56 - #Index macro
리소스
관련 비디오
WWDC24
WWDC23
-
다운로드Array
-
-
1:32 - SampleTrips models decorated with @Model
// Trip Models decorated with @Model import Foundation import SwiftData @Model class Trip { var name: String var destination: String var startDate: Date var endDate: Date var bucketList: [BucketListItem] = [BucketListItem]() var livingAccommodation: LivingAccommodation? } @Model class BucketListItem {...} @Model class LivingAccommodation {...}
-
1:43 - SampleTrips using modelContainer scene modifier
// Trip App using modelContainer Scene modifier import SwiftUI import SwiftData @main struct TripsApp: App { var body: some Scene { WindowGroup { ContentView } .modelContainer(for: Trip.self) } }
-
1:53 - SampleTrips using @Query
// Trip App using @Query import SwiftUI import SwiftData struct ContentView: View { @Query var trips: [Trip] var body: some View { NavigationSplitView { List(selection: $selection) { ForEach(trips) { trip in TripListItem(trip: trip) } } } } }
-
2:16 - SampleTrips models decorated with @Model
// Trip Models decorated with @Model import Foundation import SwiftData @Model class Trip { var name: String var destination: String var startDate: Date var endDate: Date var bucketList: [BucketListItem] = [BucketListItem]() var livingAccommodation: LivingAccommodation? } @Model class BucketListItem {...} @Model class LivingAccommodation {...}
-
3:08 - Add unique constraints to avoid duplication
// Add unique constraints to avoid duplication import SwiftData @Model class Trip { #Unique<Trip>([\.name, \.startDate, \.endDate]) var name: String var destination: String var startDate: Date var endDate: Date var bucketList: [BucketListItem] = [BucketListItem]() var livingAccommodation: LivingAccommodation? }
-
3:36 - Add .preserveValueOnDeletion to capture unique columns
// Add .preserveValueOnDeletion to capture unique columns import SwiftData @Model class Trip { #Unique<Trip>([\.name, \.startDate, \.endDate]) @Attribute(.preserveValueOnDeletion) var name: String var destination: String @Attribute(.preserveValueOnDeletion) var startDate: Date @Attribute(.preserveValueOnDeletion) var endDate: Date var bucketList: [BucketListItem] = [BucketListItem]() var livingAccommodation: LivingAccommodation? }
-
4:35 - SampleTrips using modelContainer scene modifier
// Trip App using modelContainer Scene modifier import SwiftUI import SwiftData @main struct TripsApp: App { var body: some Scene { WindowGroup { ContentView() } .modelContainer(for: Trip.self) } }
-
4:52 - Customize a model container in the app
// Customize a model container in the app import SwiftUI import SwiftData @main struct TripsApp: App { var body: some Scene { WindowGroup { ContentView() } .modelContainer(for: Trip.self, inMemory: true, isAutosaveEnabled: true, isUndoEnabled: true) } }
-
5:13 - Add a model container to the app
// Add a model container to the app import SwiftUI import SwiftData @main struct TripsApp: App { var container: ModelContainer = { do { let configuration = ModelConfiguration(schema: Schema([Trip.self]), url: fileURL) return try ModelContainer(for: Trip.self, configurations: configuration) } catch { ... } }() var body: some Scene { WindowGroup { ContentView() } .modelContainer(container) } }
-
5:59 - Use your own custom data store
// Use your own custom data store import SwiftUI import SwiftData @main struct TripsApp: App { var container: ModelContainer = { do { let configuration = JSONStoreConfiguration(schema: Schema([Trip.self]), url: jsonFileURL) return try ModelContainer(for: Trip.self, configurations: configuration) } catch { ... } }() var body: some Scene { WindowGroup { ContentView() } .modelContainer(container) } }
-
6:58 - Make preview data using traits
// Make preview data using traits struct SampleData: PreviewModifier { static func makeSharedContext() throws -> ModelContainer { let config = ModelConfiguration(isStoredInMemoryOnly: true) let container = try ModelContainer(for: Trip.self, configurations: config) Trip.makeSampleTrips(in: container) return container } func body(content: Content, context: ModelContainer) -> some View { content.modelContainer(context) } } extension PreviewTrait where T == Preview.ViewTraits { @MainActor static var sampleData: Self = .modifier(SampleData()) }
-
8:15 - Use sample data in a preview
// Use sample data in a preview import SwiftUI import SwiftData struct ContentView: View { @Query var trips: [Trip] var body: some View { ... } } #Preview(traits: .sampleData) { ContentView() }
-
8:50 - Create a preview query using @Previewable
// Create a preview query using @Previewable import SwiftUI import SwiftData #Preview(traits: .sampleData) { @Previewable @Query var trips: [Trip] BucketListItemView(trip: trips.first) }
-
9:55 - Create a predicate to find a Trip based on search text
// Create a Predicate to find a Trip based on Search Text let predicate = #Predicate<Trip> { searchText.isEmpty ? true : $0.name.localizedStandardContains(searchText) }
-
10:06 - Create a Compound Predicate to find a Trip based on Search Text
// Create a Compound Predicate to find a Trip based on Search Text let predicate = #Predicate<Trip> { searchText.isEmpty ? true : $0.name.localizedStandardContains(searchText) || $0.destination.localizedStandardContains(searchText) }
-
10:46 - Build a predicate to find Trips with BucketListItems that are not in the plan
// Build a predicate to find Trips with BucketListItems that are not in the plan let unplannedItemsExpression = #Expression<[BucketListItem], Int> { items in items.filter { !$0.isInPlan }.count } let today = Date.now let tripsWithUnplannedItems = #Predicate<Trip>{ trip // The current date falls within the trip (trip.startDate ..< trip.endDate).contains(today) && // The trip has at least one BucketListItem // where 'isInPlan' is false unplannedItemsExpression.evaluate(trip.bucketList) > 0 }
-
12:41 - Add Index for commonly used KeyPaths or combination of KeyPaths
// Add Index for commonly used KeyPaths or combination of KeyPaths import SwiftData @Model class Trip { #Unique<Trip>([\.name, \.startDate, \.endDate #Index<Trip>([\.name], [\.startDate], [\.endDate], [\.name, \.startDate, \.endDate]) var name: String var destination: String var startDate: Date var endDate: Date var bucketList: [BucketListItem] = [BucketListItem var livingAccommodation: LivingAccommodation }
-
-
찾고 계신 콘텐츠가 있나요? 위에 주제를 입력하고 원하는 내용을 바로 검색해 보세요.
쿼리를 제출하는 중에 오류가 발생했습니다. 인터넷 연결을 확인하고 다시 시도해 주세요.