관리 메뉴

김종권의 iOS 앱 개발 알아가기

[iOS - SwiftUI] Preference, PreferenceKey, preference(key:value:), onPreferenceChange() 사용 방법 (하위뷰에서 상위뷰로 데이터 넘기는 방법) 본문

iOS 기본 (SwiftUI)

[iOS - SwiftUI] Preference, PreferenceKey, preference(key:value:), onPreferenceChange() 사용 방법 (하위뷰에서 상위뷰로 데이터 넘기는 방법)

jake-kim 2022. 11. 3. 22:01

목차) SwiftUI의 기본 - 목차 링크

Preference 란?

https://developer.apple.com/documentation/swiftui/grid/preference(key:value:)

  • key와 vallue로 구성된 데이터 전달 메소드
  • 데이터 전달: 하위 뷰 -> 상위 뷰

Preference 사용 방법

  • 키를 가지고 접근
    • 1. 키 등록: preferenceKey 프로토콜 준수
    • 2. 하위뷰에서 값 송신: preference(key:value:) 메소드
    • 3. 상위뷰에서 값 수신: onPreferenceChange() 메소드

ex) 하위 뷰의 navigationTitle이 변경될때마다 부모 뷰에서 타이틀이 변경될때마다 print하기

  • 1. 키 등록: preferenceKey 프로토콜 준수
// PreferenceKey 내부 코드

@available(iOS 13.0, macOS 10.15, tvOS 13.0, watchOS 6.0, *)
public protocol PreferenceKey {
    associatedtype Value
    
    static var defaultValue: Self.Value { get }
    
    static func reduce(value: inout Self.Value, nextValue: () -> Self.Value)
}
  • preferenceKey 준수하는 NavigationBarTitleKey 정의
struct NavigationBarTitleKey: PreferenceKey {
  static var defaultValue: String = ""
  static func reduce(value: inout String, nextValue: () -> String) {
    value = nextValue()
  }
}
  • 상위뷰와 하위뷰 준비
    • 상위뷰는 NavigationView
    • 하위뷰는 NavigationView의 Link부분에 들어가는 뷰

// 상위뷰
struct ContentView: View {
  var messages: [String] {
    (0...100).map(String.init)
  }
  
  var body: some View {
    NavigationView {
      List(messages, id: \.self) { message in
        NavigationLink {
          SomeView(title: message)
        } label: {
          Text(message)
        }
      }
      .navigationBarTitle("Messages")
    }
  }
}

// 하위뷰
struct SomeView: View {
  let title: String
  
  var body: some View {
    Text(title)
      .navigationBarTitle(title)
      .preference(key: NavigationBarTitleKey.self, value: title)
  }
}
  • 2. 하위뷰에서 값 송신: preference(key:value:) 메소드
struct SomeView: View {
  let title: String
  
  var body: some View {
    Text(title)
      .navigationBarTitle(title)
      .preference(key: NavigationBarTitleKey.self, value: title) // <-
  }
}
  • 3. 상위뷰에서 값 수신: onPreferenceChange() 메소드
struct ContentView: View {
  var messages: [String] {
    (0...100).map(String.init)
  }
  
  var body: some View {
    NavigationView {
      List(messages, id: \.self) { message in
        NavigationLink {
          SomeView(title: message)
        } label: {
          Text(message)
        }
      }
      .navigationBarTitle("Messages")
    }
    .onPreferenceChange(NavigationBarTitleKey.self) { title in // <-
      print(title)
    }
  }
}

완성) 스크롤 할때마다 값 navigationTitle의 값을 print

* 전체 코드: https://github.com/JK0369/ExPreferenceKey

* 참고

https://developer.apple.com/documentation/swiftui/preferencekey

https://developer.apple.com/documentation/swiftui/grid/preference(key:value:) 

 

Comments