관리 메뉴

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

[iOS - SwiftUI] DynamicProperty 개념 (+ nonmutating set) 본문

iOS 기본 (SwiftUI)

[iOS - SwiftUI] DynamicProperty 개념 (+ nonmutating set)

jake-kim 2022. 10. 31. 22:11

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

DynamicProperty 란?

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

  • DynamicProperty는 update()라는 메소드가 있고, 내부적으로 이 메소드가 불리며 뷰를 업데이트 시키는데 사용되는 protocol
  • DynamicProperty 코드
    • update() 메소드가 있는 형태
@available(iOS 13.0, macOS 10.15, tvOS 13.0, watchOS 6.0, *)
public protocol DynamicProperty {
    mutating func update()
}
  • 주로 propertyWrapper와 같이 사용되며, 특정 값이 변경될때 뷰를 update() 시키게끔 구현

ex) Counter라는 property wrapper를 만들고 사용하는쪽에서 이 값을 변경하면 뷰에도 이 값이 업데이트되는지 확인

  • Counter모델 정의
    • DynamicProperty를 준수하는 propertyWrapper
    • 주의할점은 밖에서 value값을 수정할 수 있어야 하므로 `nonmutating set` 키워드 넣기
      • (nonmutating set 개념은 아래에서 계속)
@propertyWrapper
struct Counter: DynamicProperty {
  @State private var value = 0
  
  var wrappedValue: Int {
    get { return value }
    nonmutating set { value = newValue }
  }
}
  • 사용하는쪽
struct ContentView: View {
  @Counter private var counter
  
  var body: some View {
    Button("Button, \(counter)") {
      counter += 1
    }
  }
}

결과) 버튼을 눌렀을 때 뷰에도 값이 업데이트 되는것을 확인 가능

번외) nonmutating set 개념

  • mutating, nonmutating 키워드가 있고 mutating이면 value type 내부를 변경할 수 있고 nonmutating이면 value type 내부를 변경할 수 없는 형태
  • struct에서 set 키워드를 쓰면 앞에 mutating이라는게 생략되어있는 형태
struct Sample {
  var val = 0

  var computedVal: Int {
    get { return val }
    set { val = newValue } // mutating set { val = newValue }
  }
}
  • 명시적으로 자기 자신에 관한 set을 금지하려면 nonmutating을 작성
    • nonmutating set 안에서 self.val 값을 변경하는 코드가 있을때 컴파일 에러 발생
struct Sample {
  var val = 0

  var computedVal: Int {
    get { return val }
    nonmutating set { val = newValue } // erorr: Cannot assign to property: 'self' is immutable
  }
}
  • nonmutating set을 사용하는 경우?
    • nonmutating set 안에서 self 관련된 프로퍼티가 아닌 다른 프로퍼티를 변경하는 경우
    • ex) UserDefaults 접근
struct Sample {
  var val = 0

  var computedVal: Int {
    get { return val }
    nonmutating set {
      UserDefaults.standard.set("test", forKey: "key")
    }
  }
}
  • 위에서 알아본 DynamicProperty 내부 nonmutating set에서 self.value값을 변경하고 있어서 컴파일 에러가 날 것 같지만 정상 동작
    • 정상 동작하는 이유: @State 프로퍼티를 struct 내부에 선언해놓고 값을 변경해도 정상 동작 하게끔 SwiftUI에서 설계 했으므로, propertyWrapper 안에서도 정상 동작
@propertyWrapper
struct Counter: DynamicProperty {
  @State private var value = 0
  
  var wrappedValue: Int {
    get { return value }
    nonmutating set { value = newValue }
  }
}

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

* 참고

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

 

Comments