SwiftUI 지원EnclossingSelf 이야기
어느 날, 나는 불가사의한 기술을 발견하였다
응용 프로그램의 swift 창고를 보고 보지 못한 기술을 발견했다.
이것이 ↓
propertyWrapper입니다.그런데 wrappedValue를 방문하면 fatalError가 발매되고subscript~~의 수수께끼가 적혀 있습니다.
이subscript~~절(이하 EnclossingSelf)은 대단합니다.
아마도 Enclossing Self를 이용하여 SwiftUI의 Published 값을 업데이트함으로써 View의 재구성을 실현하는 메커니즘을 실현했기 때문일 것이다.
이번에는 이 Enclossing Self의 행동을 확인하고 SwiftUI에서 사용하는 Published를 자제했다.
@propertyWrapper
struct Observable<Value> {
private var stored: Value
~~ 中略 ~~
var wrappedValue: Value {
get { fatalError("called wrappedValue getter") }
set { fatalError("called wrappedValue setter") }
}
static subscript<EnclosingSelf>(
_enclosingInstance observed: EnclosingSelf,
wrapped wrappedKeyPath: ReferenceWritableKeyPath<EnclosingSelf, Value>,
storage storageKeyPath: ReferenceWritableKeyPath<EnclosingSelf, Self>
) -> Value {
get {
observed[keyPath: storageKeyPath].stored
}
set {
observed[keyPath: storageKeyPath].stored = newValue
}
}
}
EnclossingSelf의 코코아는 대단하죠?
EnclossingSelf를 사용하면 가능한 일
다음 코드의 출력 결과는 어떻다고 생각합니까?
hoge 한 켤레만 있기 때문에 아무것도 출력되지 않을 거예요.
class Usage {
@Wrapper var hoge: Int = 0
func addOne() {
hoge = 1
}
func fire() {
print("fire!!")
}
}
let usage = Usage()
usage.addOne()
집행 결과는 다음과 같다↓호출되지 않은 Usage입니다.Fire () 를 호출하는 중입니다.
fire!!
Mirror를 사용해도 가능하지만 EnclossingSelf를 사용하면 이 행동을 간단하게 실현할 수 있다.EnclossingSelf 설치 방법
위의 불가사의한 행동을 실현한propertywrapper.
위의 경우 EnclossingSelf에는 Usage가 있습니다.
단, wrappedValue에 set 섹션이 없으면 EnclossingSelf는
set 바이트가 있어도 set할 수 없습니다. 컴파일 오류가 발생했습니다.
enclossingSelf에 자신을 저장한 실례가 있습니다.
@propertyWrapper
struct Wrapper<Value> {
private var value: Value
init(wrappedValue: Value) {
value = wrappedValue
}
var wrappedValue: Value {
get { fatalError() }
set { fatalError() }
}
static subscript<EnclosingSelf>(
_enclosingInstance enclosingSelf: EnclosingSelf,
wrapped wrappedKeyPath: ReferenceWritableKeyPath<EnclosingSelf, Value>,
storage storageKeyPath: ReferenceWritableKeyPath<EnclosingSelf, Self>
) -> Value {
get {
return enclosingSelf[keyPath: storageKeyPath].value
}
set {
enclosingSelf[keyPath: storageKeyPath].value = newValue
(enclosingSelf as? Usage)?.fire() // Usage の fire を呼べる!!
}
}
}
Published를 해봤어요.
SwiftUI는 Observable Object입니다.활동이 ObjectWillChage에서 재생되면 View가 업데이트됩니다.
이↓ 프로그램을 실행하면 버튼을 누르면view가 업데이트되었는지 확인할 수 있습니다.
ContentViewModel.action에서 새 값이 title에 대입되면 MyPublicied의 EnclossingSelf의subscript 섹션이 호출됩니다.ContentViewModel.활동이 object WillChage에서 재생되고 ContentView가 재구성됩니다.
struct ContentView: View {
@ObservedObject var viewModel = ContentViewModel()
var body: some View {
Button("\(viewModel.title)", action: viewModel.action)
}
}
class ContentViewModel: ObservableObject {
@MyPublished var title: String = "prepared"
func action() {
title = "start!!"
}
}
@propertyWrapper
public struct MyPublished<Value> {
private var value: Value
public init(wrappedValue: Value) {
value = wrappedValue
}
public var wrappedValue: Value {
get { fatalError() }
set { fatalError() }
}
public static subscript<EnclosingSelf: ObservableObject>(
_enclosingInstance object: EnclosingSelf,
wrapped wrappedKeyPath: ReferenceWritableKeyPath<EnclosingSelf, Value>,
storage storageKeyPath: ReferenceWritableKeyPath<EnclosingSelf, Self>
) -> Value {
get {
return object[keyPath: storageKeyPath].value
}
set {
object[keyPath: storageKeyPath].value = newValue
// 値が更新されたことを通知する
(object.objectWillChange as? ObservableObjectPublisher)?.send()
}
}
}
최후
가끔 swift 창고를 보면 모르는 기능이 많아서 즐거워요.
Reference
이 문제에 관하여(SwiftUI 지원EnclossingSelf 이야기), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://zenn.dev/fuziki/articles/4153be1f9aff82a2490b텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)