View in English

  • Apple Developer
    • 시작하기

    시작하기 탐색

    • 개요
    • 알아보기
    • Apple Developer Program

    알림 받기

    • 최신 뉴스
    • Hello Developer
    • 플랫폼

    플랫폼 탐색

    • Apple 플랫폼
    • iOS
    • iPadOS
    • macOS
    • tvOS
    • visionOS
    • watchOS
    • App Store

    피처링

    • 디자인
    • 배포
    • 게임
    • 액세서리
    • 웹
    • 홈
    • CarPlay
    • 기술

    기술 탐색

    • 개요
    • Xcode
    • Swift
    • SwiftUI

    피처링

    • 손쉬운 사용
    • 앱 인텐트
    • Apple Intelligence
    • 게임
    • 머신 러닝 및 AI
    • 보안
    • Xcode Cloud
    • 커뮤니티

    커뮤니티 탐색

    • 개요
    • Apple과의 만남 이벤트
    • 커뮤니티 주도 이벤트
    • 개발자 포럼
    • 오픈 소스

    피처링

    • WWDC
    • Swift Student Challenge
    • 개발자 이야기
    • App Store 어워드
    • Apple 디자인 어워드
    • 문서

    문서 탐색

    • 문서 라이브러리
    • 기술 개요
    • 샘플 코드
    • 휴먼 인터페이스 가이드라인
    • 비디오

    릴리즈 노트

    • 피처링 업데이트
    • iOS
    • iPadOS
    • macOS
    • watchOS
    • visionOS
    • tvOS
    • Xcode
    • 다운로드

    다운로드 탐색

    • 모든 다운로드
    • 운영 체제
    • 애플리케이션
    • 디자인 리소스

    피처링

    • Xcode
    • TestFlight
    • 서체
    • SF Symbols
    • Icon Composer
    • 지원

    지원 탐색

    • 개요
    • 도움말
    • 개발자 포럼
    • 피드백 지원
    • 문의하기

    피처링

    • 계정 도움말
    • 앱 심사 지침
    • App Store Connect 도움말
    • 새로 추가될 요구 사항
    • 계약 및 지침
    • 시스템 상태
  • 빠른 링크

    • 이벤트
    • 뉴스
    • 포럼
    • 샘플 코드
    • 비디오
 

비디오

메뉴 열기 메뉴 닫기
  • 컬렉션
  • 전체 비디오
  • 소개

더 많은 비디오

  • 소개
  • 요약
  • 자막 전문
  • 코드
  • SwiftData의 새로운 기능

    SwiftData의 최신 개선 사항을 확인하세요. Codable을 사용하여 맞춤형 및 타사 유형을 유지하는 방법과 가져온 데이터를 SwiftUI 앱의 섹션으로 그룹화하는 방법을 안내합니다. 또한 ModelResultsObserver와 HistoryObserver를 사용하여 다른 곳에서 데이터 저장소 변경 사항을 관찰하는 방법을 살펴봅니다. 이를 통해 강력한 상태 객체를 활용하고, 위임 기반 아키텍처와 통합하며, 모델 업데이트에 정밀하게 반응할 수 있는 유연성을 확보할 수 있습니다.

    챕터

    • 0:00 - Introduction
    • 0:53 - Sectioning your fetches
    • 2:56 - Using custom types
    • 6:26 - Observing data stores with ResultsObserver
    • 9:41 - Observing history with HistoryObserver
    • 12:20 - Next steps

    리소스

    • SwiftData
    • Adopting SwiftData for a Core Data app
      • HD 비디오
      • SD 비디오

    관련 비디오

    WWDC26

    • 코딩 실습: SwiftData로 영속성 추가하기

    WWDC24

    • SwiftData 기록으로 모델 변경 사항 추적하기
  • 비디오 검색…

    안녕하세요, 저는 Thomas입니다. SwiftData 팀의 엔지니어입니다. 이 세션에서는 SwiftData의 새로운 기능들을 몇 가지 소개해 드리겠습니다. Apple의 2027 릴리스에 포함된 내용입니다. SwiftData를 처음 시작하시는 분이라면, 코드 실습 세션인 "Add persistence with SwiftData"를 시청하여 새 앱에서 SwiftData를 도입하는 방법을 배워보세요. Apple의 2027 릴리스는 SwiftData에 흥미로운 새 기능들을 제공합니다. 먼저, Query를 사용하는 방법을 소개할 것입니다. SwiftUI 뷰에서 섹션별로 데이터를 가져오는 방법입니다. 다음으로, 커스텀 타입을 저장하는 방법의 향상된 기능을 다룰 것입니다. 모델에 저장하는 방법입니다. 마지막으로, 훌륭한 새 API들을 다룰 것입니다. SwiftData 스토어에서 모델 및 히스토리 변경 사항을 관찰하기 위한 API들입니다. 섹션 기능을 살펴보겠습니다. 지난 몇 년 동안, 저는 계획한 모험들을 추적할 수 있는

    "SampleTrips" 앱을 개발해 왔습니다. SampleTrips는 데이터 지속성을 위해 SwiftData를, 사용자 인터페이스를 위해 SwiftUI를 사용합니다. SwiftUI와 SwiftData는 함께 잘 작동합니다. SwiftUI에서 SwiftData를 읽는 것은 뷰에 Query를 추가하는 것만큼 간단합니다. 여기서 Query는 SwiftData에서 모든 여행을 시작 날짜 순으로 정렬하여 가져옵니다. 이 쿼리의 결과는 뷰 바디에서 여행 목록을 생성하는 데 사용됩니다. SampleTrips에서 여행을 목적지별로 그룹화하는 옵션을 추가하려 합니다. 같은 장소로 여러 여행이 계획되어 있을 때, 함께 볼 수 있도록 하기 위함입니다. Apple의 2027 릴리스에서 Query에 섹션 기능이 추가됩니다. 섹션 쿼리를 만들려면 KeyPath를 전달할 수 있습니다. Trip 모델의 루트에서 시작하여 Query의 새 sectionBy 파라미터에 문자열로 이어지는 KeyPath입니다. 여기서는 Trip의 destination 속성에 대한 KeyPath를 사용하여 섹션을 만듭니다. 각 목적지에 대한 섹션입니다. Query의 wrapped value는 여전히 Trip 배열입니다. 따라서 지금 목록은 이전과 같아 보입니다. 목록을 섹션으로 나누기 위해, 현재 ForEach를 섹션으로 감싸고 두 번째 ForEach를 추가하겠습니다. 섹션에 접근하려면, property wrapper에서 쿼리에 접근합니다. 언더스코어 접두사가 붙은 "_trips" 이름을 사용합니다. 쿼리에는 섹션 목록을 반환하는 sections 속성이 있습니다. 그런 다음 SwiftUI의 ForEach를 사용하여 모든 섹션을 순회합니다. 각 섹션에는 ID 속성이 있습니다. ID는 KeyPath에서 가져온 모델의 값입니다. Query의 SectionBy 파라미터에 전달한 KeyPath입니다. 따라서 TripListView에서 ID는 해당 섹션에 있는 모든 여행의 목적지가 됩니다.

    ID를 섹션의 헤더 레이블로 사용합니다. 섹션 자체는 여행의 컬렉션이므로, 내부 ForEach를 변경하여 섹션의 각 여행에 대해 TripListItem을 생성하도록 순회합니다. 이제 모든 여행을 목적지별로 그룹화하여 볼 수 있게 되었으니, 다음 섹션으로 넘어가겠습니다. 모델에 커스텀 타입을 저장하는 향상된 기능을 자세히 살펴보겠습니다. SampleTrips 앱의 중심에는 Trip 모델이 있습니다. 이름, 목적지, 시작 및 종료 날짜와 같은 정보를 저장합니다. 현재 목적지는 Trip 모델에서 String으로 저장됩니다. MapKit에서 위치를 찾는 기능을 추가하고 싶습니다. 이미 앱에 피커를 만들어서 목적지를 검색할 수 있도록 했습니다. MapKit의 검색 API를 사용합니다. 각 위치에 대해 MapKit API는 이름과 같은 많은 메타데이터를 제공합니다. 지리적 좌표와 MKMapItem.Identifier도 포함됩니다. 이 MKMapItem.Identifier는 MapKit에서 위치를 고유하게 식별하며 위치에 대한 더 많은 메타데이터를 조회하는 데 사용할 수 있습니다. 그리고 Maps 앱에서 위치를 열 수 있습니다. 좌표를 저장하고 싶습니다. 그리고 MKMapItem.Identifier를 trip 모델에 저장하고 싶습니다. 따라서 Trip 클래스에 추가합니다. 그런데 앱을 실행하면 SwiftData가 Fatal Error를 발생시킵니다. "지속된 Struct/Enum 내의 클래스 속성은 지원되지 않습니다" - MKMapItem.Identifier가 원인으로 지목됩니다.

    SwiftData가 로드될 때, 모델에 대한 스키마를 자동으로 생성합니다. 스키마는 Model 클래스와 엔티티 간의 매핑을 정의합니다. DataStore가 지속할 수 있는 속성들입니다. 대부분의 타입에서는 이것이 자동으로 작동합니다. 하지만 Model 매크로로 어노테이션되지 않은 클래스는 자동으로 검사할 수 없으며 SwiftData는 스키마 생성에 실패합니다. MKMapItem.Identifier는 MapKit에서 제공되므로, 구현에 접근할 수 없습니다. @Model로 수정하거나 표시할 수 없으며, SwiftData도 검사할 수 없습니다. 클래스이기 때문입니다. 하지만 Codable을 준수합니다. Codable 타입은 자신을 데이터로 직렬화하는 방법을 알고 있습니다. 그리고 데이터에서 다시 인스턴스화할 수 있습니다. Apple의 2027 릴리스에서, 모델 속성을 .codable로 표시할 수 있습니다. SwiftData가 직렬화를 타입에 위임하도록 합니다. 그리고 직렬화된 표현을 저장합니다. mapItemIdentifier 속성을 codable로 표시해 보겠습니다. 이제 SampleTrips가 오류 없이 실행됩니다. 훌륭합니다. codable 속성은 SwiftData에 타입의 인코딩된 표현을 저장하도록 알려줍니다. 타입에 대한 스키마를 추론하는 대신입니다. transformable 속성과 마찬가지로, codable을 사용할 때 염두에 두어야 할 사항이 있습니다. codable 속성의 내용은 SwiftData에 불투명합니다. 이는 Predicate에서 결과를 필터링하는 데 사용할 수 없음을 의미합니다. 또는 Sort Descriptor를 사용하는 정렬에도 사용할 수 없습니다. 또한, codable 타입의 형태가 변경되면, 속성을 추가하거나 제거하는 경우, 마이그레이션이 트리거되지 않습니다. 타입의 Codable 구현은 인코딩 및 디코딩을 할 수 있어야 합니다. 순방향 및 역방향 호환 방식으로요.

    Codable 속성 사용은 SwiftData가 기본적으로 지원하지 않는 타입을 저장하는 "탈출구"로 생각할 수 있습니다. 직접 정의한 타입에는 codable 사용을 피해야 합니다. SwiftData 모델이나 지원되는 값 타입으로 모델링하면, 정렬, 필터링, 인덱싱과 같이 SwiftData의 모든 기능을 활용할 수 있습니다. 하지만 소유하지 않은 타입에 대해서는, codable을 사용하면 다른 속성들과 함께 저장할 수 있습니다. 이제 SampleTrips에서 MapKit의 위치를 선택하여 저장할 수 있습니다. 목적지의 MKMapItem.Identifier를 trip 모델의 다른 속성들과 함께 저장합니다. 이제 스토어를 모니터링하고 데이터 변경 시 알림을 받는 방법을 살펴보겠습니다. 앞서 TripListView에서 Query 매크로를 사용하여 여행들을 SwiftData 스토어에서 SwiftUI로 가져왔습니다. @Query는 강력한 도구입니다. 뷰가 나타나면 모델을 가져오고 SwiftData 스토어에서 뷰 바디에서 사용할 수 있게 됩니다. 그런 다음, 결과에 영향을 미치는 변경 사항이 있는지 스토어를 지속적으로 모니터링합니다. 예를 들어, 여행이 스토어에서 삭제되면, Query가 변경 사항을 감지합니다. 그리고 뷰는 쿼리의 새로운 결과를 반영하여 다시 렌더링됩니다. Query는 훌륭하며 SwiftUI 뷰에서 첫 번째 선택이 되어야 합니다. 하지만 앱의 SwiftUI가 아닌 부분은 어떨까요? SwiftData 스토어에서 값을 파생하는 상태 객체가 있어서 데이터가 변경되면 재계산해야 할 수도 있습니다. 또는 SceneKit으로 작성된 게임처럼 앱이 SwiftUI를 전혀 사용하지 않을 수도 있습니다.

    Apple의 2027 릴리스에서 ResultsObserver를 도입합니다. SwiftUI 뷰의 Query처럼, ResultsObserver는 데이터를 가져오고 SwiftData 스토어에서 변경 사항을 관찰합니다. 하지만 앱의 어느 곳에서나 SwiftUI 뷰에 독립적으로 작동합니다. Swift Observation을 사용합니다. 이미 알고 있는 동일한 쿼리 기능을 지원합니다. 필터링, 정렬, 그리고 앞서 다룬 섹션 기능입니다. 앞서 공유했던 데이터 흐름 다이어그램입니다. 하지만 Query가 ResultsObserver로 교체되고 View가 원하는 어떤 코드로도 교체됩니다. ResultsObserver는 데이터를 가져오고 스토어의 변경 사항을 관찰합니다. 코드는 Swift Observation을 사용하여 이러한 변경 사항에 반응할 수 있습니다. 앞서 SampleTrips 앱에 위치 정보를 추가했습니다. 여행이 계획된 모든 장소를 보기 위한 지도를 추가하고 싶습니다. SwiftUI의 MapKit 통합을 사용합니다. 하지만 지도에서 표시되는 영역을 커스터마이즈하고 싶습니다. 이를 위해 새로운 MapCameraController를 추가했습니다. 지도에 맞는 MapCameraBounds를 계산합니다. ResultsObserver를 사용하여 MapCameraBounds를 언제 재계산할지 알 수 있습니다. 이를 위해 여행에 대한 ResultsObserver를 생성합니다. 지도에서는 항상 모든 여행을 보여주고 싶으므로, 필터링을 위한 predicate나 섹션 key path를 전달하지 않겠습니다. 그런 다음 didSet 옵션과 함께 withContinuousObservation을 사용하여 여행이 변경될 때마다 콜백을 받습니다. 그리고 결과가 변경되면 지도의 범위를 재계산합니다. withContinuousObservation은 ObservationTracking 토큰을 반환합니다. 이 토큰은 관찰의 수명을 정의합니다. 업데이트를 받기 위해 클래스에 이 토큰을 저장합니다. MapCameraController의 전체 수명 동안 업데이트를 받습니다. 실제로 작동하는 모습입니다. SampleTrips를 실행하면 MapCameraController가 모든 여행이 뷰에 맞도록 지도 카메라 범위를 선택했습니다. 안타깝게도 이번 달 말에 토론토를 방문할 수 없어서, 이 여행을 삭제하겠습니다.

    ResultsObserver가 변경 사항을 감지하고 MapCameraController가 지도의 카메라 범위를 재계산합니다. ResultsObserver는 코드가 데이터 스토어의 변경 사항에 반응해야 할 때 앱 어느 곳에서나 사용할 수 있는 강력한 도구입니다. 하지만 여기서 멈추지 않았습니다. Apple의 2027 릴리스에서 히스토리 관찰도 지원합니다. 먼저, 간단한 히스토리 수업입니다. 스토어의 데이터가 변경되면 SwiftData는 변경된 모든 내용의 기록을 유지합니다. 이 히스토리를 사용하여 기능을 구축할 수 있습니다. 외부 서버와 동기화하거나, 앱 외부에서 이루어진 변경 사항에 반응하는 것과 같은 기능입니다. 앱 익스텐션에서처럼요. 데이터 스토어가 저장될 때마다 SwiftData는 히스토리 트랜잭션을 기록합니다. 히스토리 트랜잭션에는 변경된 내용에 대한 정보가 포함됩니다. 그리고 변경이 어디서 왔는지도 포함됩니다. 히스토리에서 트랜잭션을 고유하게 식별하는 토큰도 있습니다. 이 토큰은 ModelContext.fetchHistory API와 함께 사용할 수 있습니다. 더 새로운 트랜잭션을 가져옵니다. 지속적 히스토리에 대해 더 알아보려면 WWDC 2024의 "Track Model Changes with SwiftData History"를 시청하세요. Apple의 2027 릴리스의 새로운 기능은 HistoryObserver입니다. HistoryObserver는 스토어의 변경 사항에 쉽게 반응할 수 있게 해줍니다. ResultsObserver가 가져오기 결과를 관찰하는 것처럼, HistoryObserver는 지속적 히스토리를 관찰하고 새로운 트랜잭션이 추가될 때 코드가 반응하도록 합니다.

    특정 종류의 변경 사항만 알아야 한다면, HistoryObserver를 사용하면 모델 타입과 트랜잭션 작성자로 필터링할 수 있습니다. 히스토리 관찰은 유용합니다. 앱이 데이터 스토어의 일부를 동기화해야 할 때 외부 서버와 같은 다른 시스템과 동기화할 때 유용합니다. HistoryObserver에는 단 하나의 관찰 가능한 속성이 있습니다 - eventCounter입니다. 지속적 히스토리에 새로운 트랜잭션이 사용 가능해지면, eventCounter가 증가합니다. 코드는 eventCounter를 관찰하고 증가하면, ModelContext.fetchHistory API를 사용하여 최신 변경 사항을 가져옵니다.

    HistoryObserver를 사용하여 변경 사항을 동기화하는 방법의 예시입니다. 앱에서 만든 변경 사항을 외부 서버와 동기화합니다. 먼저, modelContainer에 대한 HistoryObserver를 설정합니다. 이 경우, 앱에서 만든 변경 사항에만 관심이 있으므로 "App"을 authors로 전달합니다. 서버에서 온 변경 사항을 다시 서버로 재생하지 않기 위해서입니다. 다음으로, withContinuousObservation을 사용합니다. MapCameraController처럼, 관찰 추적 토큰을 클래스에 저장하여 클래스의 수명 동안 추적이 활성 상태를 유지하도록 합니다. 관찰 클로저 내에서 eventCounter에 접근해야 합니다. Swift Observation이 무엇을 추적해야 하는지 알 수 있도록요. 마지막으로, processChanges 함수를 호출합니다. processChanges에서 ModelContext.fetchHistory API를 사용할 수 있습니다. 히스토리를 가져오고 변경 사항을 서버에 업로드합니다. 저만큼 여러분도 기대하고 계시길 바랍니다. 2027 릴리스의 SwiftData 새 기능들이 정말 기대됩니다. 섹션을 사용하여 SwiftData 가져오기를 맞춤화하세요. 다른 프레임워크의 타입을 저장할 때는 codable 속성을 사용하세요. SwiftUI 뷰 외부에서 쿼리 결과의 변경 사항에 반응하려면 ResultsObserver를 사용하세요. 마지막으로, SwiftData의 지속적 히스토리 변경 사항에 반응하려면 HistoryObserver를 사용하세요. 시청해 주셔서 감사합니다.

    • 0:01 - Sectioned fetching

      // Sectioned fetching
      
      struct TripListView: View {   
          @Query(sort: \Trip.startDate,
                 sectionBy: \.destination)
          var trips: [Trip]
      
          var body: some View: {
              List(selection: $selection) {
                  ForEach(_trips.sections) {section in
                      Section(section.id) {
                          ForEach(trips) {trip in
                              TripListItem(trip: trip)
                          }
                     }
                  }
              }
          }
      }
    • 4:59 - Using Codable

      // Using Codable
      
      import SwiftData
      
      @Model class Trip {
      
          struct Location: Codable {
              var latitude: Double
              var longitude: Double
          }
      
          var name: String
          var destination: String
      
          var startDate: Date
          var endDate: Date
      
          var location: Location?
          @Attribute(.codable) var mapItemIdentifier: MKMapItem.Identifier?
      }
    • 8:20 - // Use observation to update map bounds

      // Use observation to update map bounds
      
      @Observable @MainActor final class MapCameraController {
          private let resultsObserver: ResultsObserver<Trip, Never>
          var bounds: MapCameraBounds?
          private var token: ObservationTracking.Token?
      
          init(modelContext: ModelContext) throws {
              resultsObserver = try ResultsObserver<Trip, Never>(modelContext: modelContext)
      
              token = withContinuousObservation(options: [.didSet]) {[weak self], event in
                  self?.bounds = self?.calculateBounds(trips: resultsObserver.results)
             }
          }
      
          private func calculateBounds(trips: [Trip]) -> MapCameraBounds? { / * */ }
      }
    • 8:21 - // Using HistoryObserver to sync with a server

      // Using HistoryObserver to sync with a server
      
      @SyncActor final class ServerSync {
          private let observer: HistoryObserver
          private var token: ObservationTracking.Token?
      
          func start() throws {
              self.observer = try HistoryObserver(authors: ["App"], modelContainer: modelContainer)
              token = withContinuousObservation(options: .didSet) {[weak self] _ in
                  _ = self?.observer.eventCounter
                  self?.processChanges()
              }
          }
      
          private func processChanges() {
              // Fetch and process history transactions
          }
      }
    • 0:00 - Introduction
    • What's new in SwiftData for Apple's 2027 releases, with a preview of the agenda: sectioning fetches, using custom types, and observing data stores.

    • 0:53 - Sectioning your fetches
    • Use @Query's new sectionBy: parameter to group results by a key path. Access the underlying query via the underscore-prefixed name to iterate sections, each with an id and a collection of models — demonstrated by grouping trips by destination in SampleTrips.

    • 2:56 - Using custom types
    • Store types SwiftData can't model natively — like MKMapItem.Identifier — by marking properties with @Attribute(.codable). Treat codable as an escape hatch for external types, not types you own; modeling your own types as @Model or supported value types unlocks filtering, sorting, and migration.

    • 6:26 - Observing data stores with ResultsObserver
    • The new ResultsObserver brings Query-style fetching to non-SwiftUI code. Combine it with withContinuousObservation(didSet:) to react to model changes anywhere in your app — shown updating map camera bounds as trips change.

    • 9:41 - Observing history with HistoryObserver
    • HistoryObserver exposes a single observable eventCounter that ticks when new persistent-history transactions arrive. Pair it with ModelContext.fetchHistory() to filter by model type or transaction author — ideal for syncing changes to an external server.

    • 12:20 - Next steps
    • Recap: section your fetches, adopt codable types, react to data changes with ResultsObserver, and observe history with HistoryObserver.

Developer Footer

  • 비디오
  • WWDC26
  • SwiftData의 새로운 기능
  • 메뉴 열기 메뉴 닫기
    • iOS
    • iPadOS
    • macOS
    • tvOS
    • visionOS
    • watchOS
    메뉴 열기 메뉴 닫기
    • Swift
    • SwiftUI
    • Swift Playground
    • TestFlight
    • Xcode
    • Xcode Cloud
    • SF Symbols
    메뉴 열기 메뉴 닫기
    • 손쉬운 사용
    • 액세서리
    • Apple Intelligence
    • 앱 확장 프로그램
    • App Store
    • 오디오 및 비디오(영문)
    • 증강 현실
    • 디자인
    • 배포
    • 교육
    • 서체(영문)
    • 게임
    • 건강 및 피트니스
    • 앱 내 구입
    • 현지화
    • 지도 및 위치
    • 머신 러닝 및 AI
    • 오픈 소스(영문)
    • 보안
    • Safari 및 웹(영문)
    메뉴 열기 메뉴 닫기
    • 문서(영문)
    • 튜토리얼
    • 다운로드
    • 포럼(영문)
    • 비디오
    메뉴 열기 메뉴 닫기
    • 지원 문서
    • 문의하기
    • 버그 보고
    • 시스템 상태(영문)
    메뉴 열기 메뉴 닫기
    • Apple Developer
    • App Store Connect
    • 인증서, 식별자 및 프로파일(영문)
    • 피드백 지원
    메뉴 열기 메뉴 닫기
    • Apple Developer Program
    • Apple Developer Enterprise Program
    • App Store Small Business Program
    • MFi Program(영문)
    • Mini Apps Partner Program
    • News Partner Program(영문)
    • Video Partner Program(영문)
    • Security Bounty Program(영문)
    • Security Research Device Program(영문)
    메뉴 열기 메뉴 닫기
    • Apple과의 만남
    • Apple Developer Center
    • App Store 어워드(영문)
    • Apple 디자인 어워드
    • Apple Developer Academy(영문)
    • WWDC
    최신 뉴스 읽기.
    Apple Developer 앱 받기.
    Copyright © 2026 Apple Inc. 모든 권리 보유.
    약관 개인정보 처리방침 계약 및 지침