{"data":{"post":{"title":"Adapting Reference Semantics Model in SwiftUI - The Basics","subtitle":"","isPublished":true,"createdTime":"2023-03-02T00:00:00.000Z","lastModifiedTime":null,"license":null,"tags":["SwiftUI","Swift","Adaptor","Reference Semantics","Binding"],"category":"Programming","file":{"childMdx":{"excerpt":"Introduction Recently, one of my colleagues had been struggling with porting reference semantics…","code":{"body":"function _objectWithoutProperties(source, excluded) { if (source == null) return {}; var target = _objectWithoutPropertiesLoose(source, excluded); var key, i; if (Object.getOwnPropertySymbols) { var sourceSymbolKeys = Object.getOwnPropertySymbols(source); for (i = 0; i < sourceSymbolKeys.length; i++) { key = sourceSymbolKeys[i]; if (excluded.indexOf(key) >= 0) continue; if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue; target[key] = source[key]; } } return target; }\n\nfunction _objectWithoutPropertiesLoose(source, excluded) { if (source == null) return {}; var target = {}; var sourceKeys = Object.keys(source); var key, i; for (i = 0; i < sourceKeys.length; i++) { key = sourceKeys[i]; if (excluded.indexOf(key) >= 0) continue; target[key] = source[key]; } return target; }\n\nconst layoutProps = {};\nreturn class MDXContent extends React.Component {\n  constructor(props) {\n    super(props);\n    this.layout = null;\n  }\n\n  render() {\n    const _this$props = this.props,\n          {\n      components\n    } = _this$props,\n          props = _objectWithoutProperties(_this$props, [\"components\"]);\n\n    return React.createElement(MDXTag, {\n      name: \"wrapper\",\n      components: components\n    }, React.createElement(MDXTag, {\n      name: \"h2\",\n      components: components\n    }, `Introduction`), React.createElement(MDXTag, {\n      name: \"p\",\n      components: components\n    }, `Recently, one of my colleagues had been struggling with porting reference semantics model to SwiftUI with `, React.createElement(MDXTag, {\n      name: \"inlineCode\",\n      components: components,\n      parentName: \"p\"\n    }, `ObservableObject`), ` and `, React.createElement(MDXTag, {\n      name: \"inlineCode\",\n      components: components,\n      parentName: \"p\"\n    }, `@StateObject`), `. In this post, since there are many examples talked about porting reference semantics models to SwiftUI this way on the Internet, I'm not going to focus on the basic situation of this method. Instead, three more valuable topics can be spotted in the efforts made by my colleague and me in the process of searching for solutions to get his code to work. These topics are:`), React.createElement(MDXTag, {\n      name: \"ul\",\n      components: components\n    }, React.createElement(MDXTag, {\n      name: \"li\",\n      components: components,\n      parentName: \"ul\"\n    }, `What is the source of truth in SwiftUI?`), React.createElement(MDXTag, {\n      name: \"li\",\n      components: components,\n      parentName: \"ul\"\n    }, `How to correctly compose a source of truth in SwiftUI?`), React.createElement(MDXTag, {\n      name: \"li\",\n      components: components,\n      parentName: \"ul\"\n    }, `How to deal with asynchronous methods which are commonly used in reference semantics world when composing a source of truth.`)), React.createElement(MDXTag, {\n      name: \"p\",\n      components: components\n    }, `The mixture of misunderstanding towards these three topics is the reason that made my colleague cornered himself for over one day. I'm going to show these three topics one by one in the following story.`), React.createElement(MDXTag, {\n      name: \"h2\",\n      components: components\n    }, `The Initial Problem`), React.createElement(MDXTag, {\n      name: \"p\",\n      components: components\n    }, `My colleague wants to implement a switch that requires user confirmation before the switch is toggled on.`), React.createElement(MDXTag, {\n      name: \"p\",\n      components: components\n    }, React.createElement(MDXTag, {\n      name: \"img\",\n      components: components,\n      parentName: \"p\",\n      props: {\n        \"src\": \"/figure-1-expected-behavior-b48113f518a82b5a37b3552e66d526ee.gif\",\n        \"alt\": \"Expected Behavior\"\n      }\n    })), React.createElement(MDXTag, {\n      name: \"p\",\n      components: components\n    }, `The model behind the switch is from the legacy Objective-C world which is of reference semantics. Moreover, the setter method is an asynchronous method with a completion block.`), React.createElement(MDXTag, {\n      name: \"pre\",\n      components: components\n    }, React.createElement(MDXTag, {\n      name: \"code\",\n      components: components,\n      parentName: \"pre\",\n      props: {\n        \"className\": \"language-swift\"\n      }\n    }, `class LegacyModel {\n  \n  // The getter\n  var isOn: Bool { get }\n  \n  // The asynchronous setter\n  func setOn(_ newValue: Bool, completion: ((_ success: Bool) -> Void)?)\n  \n}\n`)), React.createElement(MDXTag, {\n      name: \"p\",\n      components: components\n    }, `Firstly, he ported the model with `, React.createElement(MDXTag, {\n      name: \"inlineCode\",\n      components: components,\n      parentName: \"p\"\n    }, `ObservableObject`), ` and adapted the asynchronous setter method with:`), React.createElement(MDXTag, {\n      name: \"ul\",\n      components: components\n    }, React.createElement(MDXTag, {\n      name: \"li\",\n      components: components,\n      parentName: \"ul\"\n    }, `A functional `, React.createElement(MDXTag, {\n      name: \"inlineCode\",\n      components: components,\n      parentName: \"li\"\n    }, `Binding`)), React.createElement(MDXTag, {\n      name: \"li\",\n      components: components,\n      parentName: \"ul\"\n    }, `A call to `, React.createElement(MDXTag, {\n      name: \"inlineCode\",\n      components: components,\n      parentName: \"li\"\n    }, `ObservableObject.objectWillChange.send()`), ` from the completion block.`)), React.createElement(MDXTag, {\n      name: \"pre\",\n      components: components\n    }, React.createElement(MDXTag, {\n      name: \"code\",\n      components: components,\n      parentName: \"pre\",\n      props: {\n        \"className\": \"language-swift\"\n      }\n    }, `import SwiftUI\nimport Combine\n\nclass Model: ObservableObject {\n\n  struct Item {\n  \n    let description: String\n    \n    let isOn: Binding<Bool>\n  \n  }\n\n  @Published\n  var items:  [Item] = []\n  \n  init() {\n    items = [\n      Item(\n        description: \"Test\",\n        isOn: Binding {\n          LegecyModel.shared.isOn\n        } set: { newValue, tnx in\n          // The value is set asynchronously\n          LegecyModel.shared.setOn(newValue) {\n            DispatchQueue.main.async {\n              self.objectWillChange.send()\n            }\n          }\n        }\n      )\n    ]\n  }\n  \n}\n`)), React.createElement(MDXTag, {\n      name: \"p\",\n      components: components\n    }, `And here is the code that implements the user interface.`), React.createElement(MDXTag, {\n      name: \"pre\",\n      components: components\n    }, React.createElement(MDXTag, {\n      name: \"code\",\n      components: components,\n      parentName: \"pre\",\n      props: {\n        \"className\": \"language-swift\"\n      }\n    }, `struct ContentView: View {\n\n  @StateObject\n  var model = Model()\n  \n  var body: some View {\n    ItemView(item: model.items[0])\n  }\n  \n  struct ItemView: View {\n  \n    var item: Model.Item\n    \n    @State\n    var needsUserConfirm: Bool = false\n    \n    var body: some View {\n      Button(item.description) {\n        if item.isOn.wrappedValue {\n          item.isOn.wrappedValue = false\n        } else {\n          needsUserConfirm = true\n        }\n      }\n      .buttonStyle(ToggleButtonStyle(isOn: item.isOn.wrappedValue))\n      .alert(\"Sure?\", isPresented: $needsUserConfirm) {\n        Button(\"OK\") {\n          item.isOn.wrappedValue = true\n        }\n        Button(\"Cancel\", role: .cancel) {}\n      }\n    }\n  }\n}\n\n// We need toggle's visual style but a button's\n// behavior.\nstruct ToggleButtonStyle: ButtonStyle {\n  \n  var isOn: Bool\n  \n  func makeBody(configuration: Configuration) -> some View {\n    Toggle(isOn: .constant(isOn)) {\n      configuration.label\n    }\n    .allowsHitTesting(false)\n    .contentShape(Rectangle())\n  }\n  \n}\n`)), React.createElement(MDXTag, {\n      name: \"p\",\n      components: components\n    }, `But he can never get the switch to be toggled on by tapping the \"OK\" button with the code above.`), React.createElement(MDXTag, {\n      name: \"p\",\n      components: components\n    }, React.createElement(MDXTag, {\n      name: \"img\",\n      components: components,\n      parentName: \"p\",\n      props: {\n        \"src\": \"/figure-1-expected-behavior-b48113f518a82b5a37b3552e66d526ee.gif\",\n        \"alt\": \"Incorrect Behavior\"\n      }\n    })), React.createElement(MDXTag, {\n      name: \"h2\",\n      components: components\n    }, `Hack 1: What Drives SwiftUI's Updates?`), React.createElement(MDXTag, {\n      name: \"p\",\n      components: components\n    }, `With the first glimpse of the problem, I thought that his code didn't honor SwiftUI's value-driven update pattern.`), React.createElement(MDXTag, {\n      name: \"p\",\n      components: components\n    }, `SwiftUI updates along with value changes. Since the `, React.createElement(MDXTag, {\n      name: \"inlineCode\",\n      components: components,\n      parentName: \"p\"\n    }, `Model.Item`), ` has no stored values changed (all `, React.createElement(MDXTag, {\n      name: \"inlineCode\",\n      components: components,\n      parentName: \"p\"\n    }, `let`), ` properties), SwiftUI cannot detect the changes behind the `, React.createElement(MDXTag, {\n      name: \"inlineCode\",\n      components: components,\n      parentName: \"p\"\n    }, `Binding`), `.`), React.createElement(MDXTag, {\n      name: \"pre\",\n      components: components\n    }, React.createElement(MDXTag, {\n      name: \"code\",\n      components: components,\n      parentName: \"pre\",\n      props: {\n        \"className\": \"language-swift\"\n      }\n    }, `class Model: ObservableObject {\n\n  struct Item {\n  \n    let description: String\n    \n    let isOn: Binding<Bool>\n  \n  }\n  \n}\n`)), React.createElement(MDXTag, {\n      name: \"p\",\n      components: components\n    }, `We can verify this by running the program with breakpoints set. The `, React.createElement(MDXTag, {\n      name: \"inlineCode\",\n      components: components,\n      parentName: \"p\"\n    }, `ItemView.body`), ` would not get evaluated after `, React.createElement(MDXTag, {\n      name: \"inlineCode\",\n      components: components,\n      parentName: \"p\"\n    }, `self.objectWillChange.send()`), ` was invoked.`), React.createElement(MDXTag, {\n      name: \"p\",\n      components: components\n    }, React.createElement(MDXTag, {\n      name: \"img\",\n      components: components,\n      parentName: \"p\",\n      props: {\n        \"src\": \"/figure-3-breakpoint-for-hack-1-8c42da154fc61c9a247f270a6552b445.gif\",\n        \"alt\": \"Breakpoint for Hack 1\"\n      }\n    })), React.createElement(MDXTag, {\n      name: \"p\",\n      components: components\n    }, `To solve this issue with minimal effort, to help my colleague to meet his deadline, I suggested my colleague extend the model that fed to SwiftUI like this:`), React.createElement(MDXTag, {\n      name: \"pre\",\n      components: components\n    }, React.createElement(MDXTag, {\n      name: \"code\",\n      components: components,\n      parentName: \"pre\",\n      props: {\n        \"className\": \"language-swift\"\n      }\n    }, `class Model: ObservableObject {\n\n  struct Item {\n  \n    let description: String\n    \n    let isOn: Binding<Bool>\n    \n    // The added field\n    var seed: UInt8\n  \n  }\n  \n}\n`)), React.createElement(MDXTag, {\n      name: \"p\",\n      components: components\n    }, `Then he can drive SwiftUI to evaluate `, React.createElement(MDXTag, {\n      name: \"inlineCode\",\n      components: components,\n      parentName: \"p\"\n    }, `ItemView.body`), ` by increasing the `, React.createElement(MDXTag, {\n      name: \"inlineCode\",\n      components: components,\n      parentName: \"p\"\n    }, `Model.Item.seed`), ` at the time that he invokes `, React.createElement(MDXTag, {\n      name: \"inlineCode\",\n      components: components,\n      parentName: \"p\"\n    }, `self.objectWillChange.send()`), `:`), React.createElement(MDXTag, {\n      name: \"pre\",\n      components: components\n    }, React.createElement(MDXTag, {\n      name: \"code\",\n      components: components,\n      parentName: \"pre\",\n      props: {\n        \"className\": \"language-swift\"\n      }\n    }, `class Model: ObservableObject {\n\n  ...\n  \n  init() {\n    items = [\n      Item(\n        description: \"Test\",\n        isOn: Binding {\n          LegecyModel.shared.isOn\n        } set: { newValue, tnx in\n          // The value is set asynchronously\n          LegecyModel.shared.setOn(newValue) {\n            DispatchQueue.main.async {\n              self.objectWillChange.send()\n              self.items[0].seed &+= 1\n            }\n          }\n        }\n      )\n    ]\n  }\n}\n\nstruct ContentView: View {\n\n  ...\n  \n  struct ItemView: View {\n    \n    ...\n    \n    var body: some View {\n      Button(item.description) {\n        ...\n      }\n      .buttonStyle(BySeedUpdateToggleButtonStyle(isOn: item.isOn.wrappedValue, seed: item.seed))\n      ...\n    }\n    \n  }\n  \n}\n\nstruct BySeedUpdateToggleButtonStyle: ButtonStyle {\n  \n  var isOn: Bool\n  \n  var seed: Int\n  \n  func makeBody(configuration: Configuration) -> some View {\n    Toggle(isOn: .constant(isOn)) {\n      configuration.label\n    }\n    .allowsHitTesting(false)\n    .contentShape(Rectangle())\n  }\n  \n}\n`)), React.createElement(MDXTag, {\n      name: \"p\",\n      components: components\n    }, `After he modified the code, and built-and-ran the program, we were waiting for a miracle to happen -- but nothing changed eventually. He still cannot make the switch to be toggled on by tapping the \"OK\" button.`), React.createElement(MDXTag, {\n      name: \"p\",\n      components: components\n    }, React.createElement(MDXTag, {\n      name: \"img\",\n      components: components,\n      parentName: \"p\",\n      props: {\n        \"src\": \"/figure-2-incorrect-behavior-2119e086393b5640f81cfb4e291ebbdd.gif\",\n        \"alt\": \"Incorrect Behavior\"\n      }\n    })), React.createElement(MDXTag, {\n      name: \"p\",\n      components: components\n    }, `But the `, React.createElement(MDXTag, {\n      name: \"inlineCode\",\n      components: components,\n      parentName: \"p\"\n    }, `ItemView.body`), ` would be evaluated now.`), React.createElement(MDXTag, {\n      name: \"p\",\n      components: components\n    }, React.createElement(MDXTag, {\n      name: \"img\",\n      components: components,\n      parentName: \"p\",\n      props: {\n        \"src\": \"/figure-5-breakpoint-for-hack-2-a5bd285b44523312d75a9f2c7f3eadfa.gif\",\n        \"alt\": \"Breakpoint for Hack 2\"\n      }\n    })), React.createElement(MDXTag, {\n      name: \"p\",\n      components: components\n    }, `What's wrong with this hack?`), React.createElement(MDXTag, {\n      name: \"h2\",\n      components: components\n    }, `Hack 2: Understanding Dynamic Property Update`), React.createElement(MDXTag, {\n      name: \"p\",\n      components: components\n    }, `By setting breakpoints in his code, we can find that even we forced SwiftUI to evaluate the `, React.createElement(MDXTag, {\n      name: \"inlineCode\",\n      components: components,\n      parentName: \"p\"\n    }, `ItemView.body`), ` by increasing `, React.createElement(MDXTag, {\n      name: \"inlineCode\",\n      components: components,\n      parentName: \"p\"\n    }, `Model.Item.seed`), `, the `, React.createElement(MDXTag, {\n      name: \"inlineCode\",\n      components: components,\n      parentName: \"p\"\n    }, `Binding`), `'s `, React.createElement(MDXTag, {\n      name: \"inlineCode\",\n      components: components,\n      parentName: \"p\"\n    }, `wrappedValue`), ` is not changed.`), React.createElement(MDXTag, {\n      name: \"p\",\n      components: components\n    }, React.createElement(MDXTag, {\n      name: \"a\",\n      components: components,\n      parentName: \"p\",\n      props: {\n        \"href\": \"/static/ef5dcad1c21508565ce15d439397181e/99f17/figure-6-po-binding.webp\"\n      }\n    }, React.createElement(MDXTag, {\n      name: \"picture\",\n      components: components,\n      parentName: \"a\"\n    }, `\n  `, React.createElement(MDXTag, {\n      name: \"source\",\n      components: components,\n      parentName: \"picture\",\n      props: {\n        \"src\": \"/static/ef5dcad1c21508565ce15d439397181e/0cc25/figure-6-po-binding.png\",\n        \"srcSet\": [\"/static/ef5dcad1c21508565ce15d439397181e/5116e/figure-6-po-binding.png 178w\", \"/static/ef5dcad1c21508565ce15d439397181e/92f55/figure-6-po-binding.png 356w\", \"/static/ef5dcad1c21508565ce15d439397181e/0cc25/figure-6-po-binding.png 712w\", \"/static/ef5dcad1c21508565ce15d439397181e/7ae06/figure-6-po-binding.png 1068w\", \"/static/ef5dcad1c21508565ce15d439397181e/eee47/figure-6-po-binding.png 1424w\", \"/static/ef5dcad1c21508565ce15d439397181e/e8042/figure-6-po-binding.png 1652w\"],\n        \"sizes\": \"(max-width: 712px) 100vw, 712px\"\n      }\n    }), React.createElement(MDXTag, {\n      name: \"source\",\n      components: components,\n      parentName: \"picture\",\n      props: {\n        \"src\": \"/static/ef5dcad1c21508565ce15d439397181e/690c8/figure-6-po-binding.webp\",\n        \"srcSet\": [\"/static/ef5dcad1c21508565ce15d439397181e/25c8a/figure-6-po-binding.webp 178w\", \"/static/ef5dcad1c21508565ce15d439397181e/60698/figure-6-po-binding.webp 356w\", \"/static/ef5dcad1c21508565ce15d439397181e/690c8/figure-6-po-binding.webp 712w\", \"/static/ef5dcad1c21508565ce15d439397181e/d7e52/figure-6-po-binding.webp 1068w\", \"/static/ef5dcad1c21508565ce15d439397181e/456ef/figure-6-po-binding.webp 1424w\", \"/static/ef5dcad1c21508565ce15d439397181e/99f17/figure-6-po-binding.webp 1652w\"],\n        \"sizes\": \"(max-width: 712px) 100vw, 712px\"\n      }\n    }), `\n  `, React.createElement(MDXTag, {\n      name: \"img\",\n      components: components,\n      parentName: \"picture\",\n      props: {\n        \"src\": \"/static/ef5dcad1c21508565ce15d439397181e/99f17/figure-6-po-binding.webp\",\n        \"alt\": \"po Binding\",\n        \"title\": \"null\",\n        \"width\": 712,\n        \"height\": 164,\n        \"loading\": \"lazy\"\n      }\n    })))), React.createElement(MDXTag, {\n      name: \"p\",\n      components: components\n    }, `Since my colleague used functional `, React.createElement(MDXTag, {\n      name: \"inlineCode\",\n      components: components,\n      parentName: \"p\"\n    }, `Binding`), ` instead of a `, React.createElement(MDXTag, {\n      name: \"inlineCode\",\n      components: components,\n      parentName: \"p\"\n    }, `Binding`), ` projected from `, React.createElement(MDXTag, {\n      name: \"inlineCode\",\n      components: components,\n      parentName: \"p\"\n    }, `State`), `, you may intuitively think that the `, React.createElement(MDXTag, {\n      name: \"inlineCode\",\n      components: components,\n      parentName: \"p\"\n    }, `wrappedValue`), ` of the functional `, React.createElement(MDXTag, {\n      name: \"inlineCode\",\n      components: components,\n      parentName: \"p\"\n    }, `Binding`), ` directly returns the result of the `, React.createElement(MDXTag, {\n      name: \"inlineCode\",\n      components: components,\n      parentName: \"p\"\n    }, `get`), ` closure which is used in the `, React.createElement(MDXTag, {\n      name: \"inlineCode\",\n      components: components,\n      parentName: \"p\"\n    }, `Binding`), `’s instantiation. This can be represented with the following pseudo-code.`), React.createElement(MDXTag, {\n      name: \"pre\",\n      components: components\n    }, React.createElement(MDXTag, {\n      name: \"code\",\n      components: components,\n      parentName: \"pre\",\n      props: {\n        \"className\": \"language-swift\"\n      }\n    }, `@propertyWrapper\nstruct Binding<Value> {\n\n  let transaction: Transaction\n\n  let getter: () -> Value\n  \n  let setter: (Value, Transaction) -> Void\n  \n  var wrappedValue: Value {\n    get {\n      getter()\n    }\n    set {\n      setter(newValue, transaction)\n    }\n  }\n\n}\n`)), React.createElement(MDXTag, {\n      name: \"p\",\n      components: components\n    }, `But this is implementation-oriented -- firstly you know the underlying implementation of the `, React.createElement(MDXTag, {\n      name: \"inlineCode\",\n      components: components,\n      parentName: \"p\"\n    }, `Binding`), ` that was used, then you inferred this behavior based on the fact about the underlying implementation.`), React.createElement(MDXTag, {\n      name: \"h3\",\n      components: components\n    }, `A Deeper Understanding of Binding`), React.createElement(MDXTag, {\n      name: \"p\",\n      components: components\n    }, `To understand the bug-like behavior that we observed on `, React.createElement(MDXTag, {\n      name: \"inlineCode\",\n      components: components,\n      parentName: \"p\"\n    }, `Binding`), ` in the demo above, we have to get a deeper understanding of `, React.createElement(MDXTag, {\n      name: \"inlineCode\",\n      components: components,\n      parentName: \"p\"\n    }, `Binding`)), React.createElement(MDXTag, {\n      name: \"p\",\n      components: components\n    }, React.createElement(MDXTag, {\n      name: \"inlineCode\",\n      components: components,\n      parentName: \"p\"\n    }, `Binding`), ` in SwiftUI is special -- `, React.createElement(MDXTag, {\n      name: \"inlineCode\",\n      components: components,\n      parentName: \"p\"\n    }, `Binding`), ` is the \"reference\" to the managed dynamic data in SwiftUI. The “managed dynamic data” here means the dynamic properties that can project `, React.createElement(MDXTag, {\n      name: \"inlineCode\",\n      components: components,\n      parentName: \"p\"\n    }, `Binding`), `s. SwiftUI's documentation entitled these dynamic properties with \"sources of truths\". We can get this from `, React.createElement(MDXTag, {\n      name: \"inlineCode\",\n      components: components,\n      parentName: \"p\"\n    }, `Binding`), `'s documentation which shipped with iOS 16's SDK:`), React.createElement(MDXTag, {\n      name: \"blockquote\",\n      components: components\n    }, React.createElement(MDXTag, {\n      name: \"p\",\n      components: components,\n      parentName: \"blockquote\"\n    }, `Binding`), React.createElement(MDXTag, {\n      name: \"p\",\n      components: components,\n      parentName: \"blockquote\"\n    }, `A property wrapper type that can read and write a value owned by a source of truth.`)), React.createElement(MDXTag, {\n      name: \"p\",\n      components: components\n    }, `But I think the \"managed dynamic data\" is a more unambiguously title for these dynamic properties -- because you have to make these dynamic properties get managed by SwiftUI then you can make them work as you expect. To get these dynamic properties managed by SwiftUI, you have to install them directly on `, React.createElement(MDXTag, {\n      name: \"inlineCode\",\n      components: components,\n      parentName: \"p\"\n    }, `View`), `, `, React.createElement(MDXTag, {\n      name: \"inlineCode\",\n      components: components,\n      parentName: \"p\"\n    }, `Gesture`), ` or other user interface structural types that shipped with SwiftUI:`), React.createElement(MDXTag, {\n      name: \"pre\",\n      components: components\n    }, React.createElement(MDXTag, {\n      name: \"code\",\n      components: components,\n      parentName: \"pre\",\n      props: {\n        \"className\": \"language-swift\"\n      }\n    }, `struct ContentView: View {\n\n  // Directly install on \\`View\\`\n  @State\n  var data: Int = 0\n  \n  var body: some View {\n    ...\n  }\n\n}\n`)), React.createElement(MDXTag, {\n      name: \"p\",\n      components: components\n    }, `Thus we can know that the first issue that the `, React.createElement(MDXTag, {\n      name: \"inlineCode\",\n      components: components,\n      parentName: \"p\"\n    }, `Model.Item`), ` raised is the `, React.createElement(MDXTag, {\n      name: \"inlineCode\",\n      components: components,\n      parentName: \"p\"\n    }, `Binding`), ` property of `, React.createElement(MDXTag, {\n      name: \"inlineCode\",\n      components: components,\n      parentName: \"p\"\n    }, `Model.Item`), ` is not installed on `, React.createElement(MDXTag, {\n      name: \"inlineCode\",\n      components: components,\n      parentName: \"p\"\n    }, `View`), `.`), React.createElement(MDXTag, {\n      name: \"p\",\n      components: components\n    }, `On the other hand, since `, React.createElement(MDXTag, {\n      name: \"inlineCode\",\n      components: components,\n      parentName: \"p\"\n    }, `Binding`), ` is designed to be a reference to the managed dynamic data and SwiftUI implements a transactional update pattern which to provide a consistent view of the managed dynamic data during the dependency graph updating, `, React.createElement(MDXTag, {\n      name: \"inlineCode\",\n      components: components,\n      parentName: \"p\"\n    }, `Binding`), ` also honors this pattern. In detail, `, React.createElement(MDXTag, {\n      name: \"inlineCode\",\n      components: components,\n      parentName: \"p\"\n    }, `Binding`)), React.createElement(MDXTag, {\n      name: \"ul\",\n      components: components\n    }, React.createElement(MDXTag, {\n      name: \"li\",\n      components: components,\n      parentName: \"ul\"\n    }, `caches the latest value at the instantiation time and the time that the dependency graph updates it;`), React.createElement(MDXTag, {\n      name: \"li\",\n      components: components,\n      parentName: \"ul\"\n    }, `returns the cached value when the dependency graph is updating.`)), React.createElement(MDXTag, {\n      name: \"p\",\n      components: components\n    }, React.createElement(MDXTag, {\n      name: \"a\",\n      components: components,\n      parentName: \"p\",\n      props: {\n        \"href\": \"/static/673b68fe7b16bebd43972e7770e5e730/d5e03/figure-7-binding-update.png\"\n      }\n    }, React.createElement(MDXTag, {\n      name: \"img\",\n      components: components,\n      parentName: \"a\",\n      props: {\n        \"title\": \"null\",\n        \"alt\": \"Binding Update\",\n        \"src\": \"/static/673b68fe7b16bebd43972e7770e5e730/d5e03/figure-7-binding-update.png\",\n        \"srcSet\": [\"/static/673b68fe7b16bebd43972e7770e5e730/d5e03/figure-7-binding-update.png 1x\", \"/static/11b5c9d0c3735f67ab688e38a3325491/fd824/figure-7-binding-update%402x.png 2x\", \"/static/28f233658f317bad8a4f990ecd34edea/7d055/figure-7-binding-update%403x.png 3x\"],\n        \"loading\": \"lazy\"\n      }\n    }))), React.createElement(MDXTag, {\n      name: \"p\",\n      components: components\n    }, `This mechanism makes the `, React.createElement(MDXTag, {\n      name: \"inlineCode\",\n      components: components,\n      parentName: \"p\"\n    }, `Model.Item`), ` raised its second issue: the `, React.createElement(MDXTag, {\n      name: \"inlineCode\",\n      components: components,\n      parentName: \"p\"\n    }, `Binding`), ` always returns the value at the instantiation time when we read it at `, React.createElement(MDXTag, {\n      name: \"inlineCode\",\n      components: components,\n      parentName: \"p\"\n    }, `View.body`), `'s evaluation time. Since the evaluation of `, React.createElement(MDXTag, {\n      name: \"inlineCode\",\n      components: components,\n      parentName: \"p\"\n    }, `View.body`), ` happened during the dependency graph update, by honoring the transactional update pattern, `, React.createElement(MDXTag, {\n      name: \"inlineCode\",\n      components: components,\n      parentName: \"p\"\n    }, `Binding`), ` would also return its cached value. Since the `, React.createElement(MDXTag, {\n      name: \"inlineCode\",\n      components: components,\n      parentName: \"p\"\n    }, `Binding`), ` property of `, React.createElement(MDXTag, {\n      name: \"inlineCode\",\n      components: components,\n      parentName: \"p\"\n    }, `Model.Item`), ` is not managed by SwiftUI, it has no chance to get its cached value updated. Thus we can see the bug-like behavior above.`), React.createElement(MDXTag, {\n      name: \"h3\",\n      components: components\n    }, `Make a Hack That Works`), React.createElement(MDXTag, {\n      name: \"p\",\n      components: components\n    }, `So is there still a way that takes minimal effort to hack the code to work?`), React.createElement(MDXTag, {\n      name: \"p\",\n      components: components\n    }, `Yes, there still is.`), React.createElement(MDXTag, {\n      name: \"p\",\n      components: components\n    }, `For third-party defined types that conform to `, React.createElement(MDXTag, {\n      name: \"inlineCode\",\n      components: components,\n      parentName: \"p\"\n    }, `DynamicProperty`), ` protocol, there is an `, React.createElement(MDXTag, {\n      name: \"inlineCode\",\n      components: components,\n      parentName: \"p\"\n    }, `update`), ` method would be invoked before the installed `, React.createElement(MDXTag, {\n      name: \"inlineCode\",\n      components: components,\n      parentName: \"p\"\n    }, `View`), `'s `, React.createElement(MDXTag, {\n      name: \"inlineCode\",\n      components: components,\n      parentName: \"p\"\n    }, `body`), ` gets evaluated. With it, we still have an opportunity to manually \"manage\" the update of the `, React.createElement(MDXTag, {\n      name: \"inlineCode\",\n      components: components,\n      parentName: \"p\"\n    }, `Binding`), ` property on `, React.createElement(MDXTag, {\n      name: \"inlineCode\",\n      components: components,\n      parentName: \"p\"\n    }, `Model.Item`), ` before the evaluation of `, React.createElement(MDXTag, {\n      name: \"inlineCode\",\n      components: components,\n      parentName: \"p\"\n    }, `ItemView.body`), ` began.`), React.createElement(MDXTag, {\n      name: \"p\",\n      components: components\n    }, `Thus we can create a new dynamic property wrapper that wraps `, React.createElement(MDXTag, {\n      name: \"inlineCode\",\n      components: components,\n      parentName: \"p\"\n    }, `@StateObject`), ` and manually resets the `, React.createElement(MDXTag, {\n      name: \"inlineCode\",\n      components: components,\n      parentName: \"p\"\n    }, `@StateObject`), `'s contents in `, React.createElement(MDXTag, {\n      name: \"inlineCode\",\n      components: components,\n      parentName: \"p\"\n    }, `DynamicProperty.update`), `.`), React.createElement(MDXTag, {\n      name: \"pre\",\n      components: components\n    }, React.createElement(MDXTag, {\n      name: \"code\",\n      components: components,\n      parentName: \"pre\",\n      props: {\n        \"className\": \"language-swift\"\n      }\n    }, `import SwiftUI\n\nprotocol Remakable {\n  \n  func remake()\n  \n}\n\n@propertyWrapper\nstruct RemakableStateObject<ObjectType: ObservableObject & Remakable>: DynamicProperty {\n  \n  var wrappedValue: StateObject<ObjectType>\n  \n  func update() {\n    wrappedValue.wrappedValue.remake()\n  }\n  \n}\n`)), React.createElement(MDXTag, {\n      name: \"p\",\n      components: components\n    }, `Then we have to modify the `, React.createElement(MDXTag, {\n      name: \"inlineCode\",\n      components: components,\n      parentName: \"p\"\n    }, `Model`), ` to conform `, React.createElement(MDXTag, {\n      name: \"inlineCode\",\n      components: components,\n      parentName: \"p\"\n    }, `Remakable`), ` protocol we just declared.`), React.createElement(MDXTag, {\n      name: \"pre\",\n      components: components\n    }, React.createElement(MDXTag, {\n      name: \"code\",\n      components: components,\n      parentName: \"pre\",\n      props: {\n        \"className\": \"language-swift\"\n      }\n    }, `class Model: Remakable, ObservableObject {\n  \n  struct Item {\n    \n    var description: String\n    \n    var binding: Binding<Bool>\n    \n  }\n  \n  var items: [Item] = []\n  \n  init() {\n    remake()\n  }\n  \n  func remake() {\n    items = [\n     Item(description: \"Test\", isOn: Binding(get: {\n       LegacyModel.shared.isOn\n     }, set: { [unowned self] value in\n       LegacyModel.shared.setOn(value) { _ in\n         DispatchQueue.main.async {\n           self.objectWillChange.send()\n         }\n       }\n     }))\n   ]\n  }\n  \n}\n`)), React.createElement(MDXTag, {\n      name: \"p\",\n      components: components\n    }, `Finally, we need to wrap the `, React.createElement(MDXTag, {\n      name: \"inlineCode\",\n      components: components,\n      parentName: \"p\"\n    }, `@StateObject var model: Model`), ` with an additional property wrapper -- `, React.createElement(MDXTag, {\n      name: \"inlineCode\",\n      components: components,\n      parentName: \"p\"\n    }, `@RemakableStateObject`), ` to make the code work.`), React.createElement(MDXTag, {\n      name: \"pre\",\n      components: components\n    }, React.createElement(MDXTag, {\n      name: \"code\",\n      components: components,\n      parentName: \"pre\",\n      props: {\n        \"className\": \"language-swift\"\n      }\n    }, `struct ContentView: View {\n  \n  @RemakableStateObject\n  @StateObject\n  var model = Model()\n  \n  ...\n  \n}\n`)), React.createElement(MDXTag, {\n      name: \"p\",\n      components: components\n    }, `Now we can get the switch to be toggled on by tapping the \"OK\" button.`), React.createElement(MDXTag, {\n      name: \"p\",\n      components: components\n    }, React.createElement(MDXTag, {\n      name: \"img\",\n      components: components,\n      parentName: \"p\",\n      props: {\n        \"src\": \"/figure-1-expected-behavior-b48113f518a82b5a37b3552e66d526ee.gif\",\n        \"alt\": \"Hack 2 Behavior\"\n      }\n    })), React.createElement(MDXTag, {\n      name: \"h2\",\n      components: components\n    }, `Suggested Solution: Compose a Qualified Source of Truth`), React.createElement(MDXTag, {\n      name: \"p\",\n      components: components\n    }, `My colleague had been insisting on wrapping the reference semantics model with functional `, React.createElement(MDXTag, {\n      name: \"inlineCode\",\n      components: components,\n      parentName: \"p\"\n    }, `Binding`), ` because he treats the wrapped reference semantics model as \"the single source of truth\". This misunderstood the concept in SwiftUI.`), React.createElement(MDXTag, {\n      name: \"p\",\n      components: components\n    }, `With the explanation above, we already know that a qualified \"source of truth\" in SwiftUI means a dynamic property installed on `, React.createElement(MDXTag, {\n      name: \"inlineCode\",\n      components: components,\n      parentName: \"p\"\n    }, `View`), `, `, React.createElement(MDXTag, {\n      name: \"inlineCode\",\n      components: components,\n      parentName: \"p\"\n    }, `Gesture`), ` or other structural user interface types. Compose a \"source of truth\" this way is the simplest and the most proper way to port reference semantics model to SwiftUI's world.`), React.createElement(MDXTag, {\n      name: \"p\",\n      components: components\n    }, `For my colleague's case, we can make the model conform to `, React.createElement(MDXTag, {\n      name: \"inlineCode\",\n      components: components,\n      parentName: \"p\"\n    }, `ObservableObject`), ` but we have to change the `, React.createElement(MDXTag, {\n      name: \"inlineCode\",\n      components: components,\n      parentName: \"p\"\n    }, `isOn`), ` into a plain `, React.createElement(MDXTag, {\n      name: \"inlineCode\",\n      components: components,\n      parentName: \"p\"\n    }, `Bool`), `.`), React.createElement(MDXTag, {\n      name: \"pre\",\n      components: components\n    }, React.createElement(MDXTag, {\n      name: \"code\",\n      components: components,\n      parentName: \"pre\",\n      props: {\n        \"className\": \"language-swift\"\n      }\n    }, `class Model: ObservableObject {\n\n  struct Item {\n  \n    let description: String\n    \n    let isOn: Bool\n  \n  }\n  \n}\n`)), React.createElement(MDXTag, {\n      name: \"p\",\n      components: components\n    }, `But how to deal with the asynchronous setter on the reference semantics model? The solution is that: we need to set the new value with a \"reference\" to the `, React.createElement(MDXTag, {\n      name: \"inlineCode\",\n      components: components,\n      parentName: \"p\"\n    }, `Model.Item`), ` in `, React.createElement(MDXTag, {\n      name: \"inlineCode\",\n      components: components,\n      parentName: \"p\"\n    }, `@StateObject var model: Model`), ` after the asynchronous setter completes its work.`), React.createElement(MDXTag, {\n      name: \"p\",\n      components: components\n    }, `As I mentioned above, the \"reference\" here means `, React.createElement(MDXTag, {\n      name: \"inlineCode\",\n      components: components,\n      parentName: \"p\"\n    }, `Binding`), `.`), React.createElement(MDXTag, {\n      name: \"p\",\n      components: components\n    }, `Firstly, we need to get the `, React.createElement(MDXTag, {\n      name: \"inlineCode\",\n      components: components,\n      parentName: \"p\"\n    }, `Binding`), ` of the data we want to modify after the asynchronous setter is completed. We can call `, React.createElement(MDXTag, {\n      name: \"inlineCode\",\n      components: components,\n      parentName: \"p\"\n    }, `$item`), ` in the `, React.createElement(MDXTag, {\n      name: \"inlineCode\",\n      components: components,\n      parentName: \"p\"\n    }, `ItemView`), ` to get a `, React.createElement(MDXTag, {\n      name: \"inlineCode\",\n      components: components,\n      parentName: \"p\"\n    }, `Binding`), ` of `, React.createElement(MDXTag, {\n      name: \"inlineCode\",\n      components: components,\n      parentName: \"p\"\n    }, `Model.Item`), `.`), React.createElement(MDXTag, {\n      name: \"pre\",\n      components: components\n    }, React.createElement(MDXTag, {\n      name: \"code\",\n      components: components,\n      parentName: \"pre\",\n      props: {\n        \"className\": \"language-swift\"\n      }\n    }, `struct ItemView: View {\n    \n  @Binding\n  var item: Model\n    \n  @State\n  var needsUserConfirm: Bool = false\n    \n  var body: some View {\n    Button(item.description) {\n      if item.isOn {\n        // The \\`setOn\\` method encapsulates\n        // asynchronous access to the setter\n        item.setOn($item, false)\n      } else {\n        needsUserConfirm = true\n      }\n    }\n    ...\n  }\n`)), React.createElement(MDXTag, {\n      name: \"p\",\n      components: components\n    }, `Then declare a `, React.createElement(MDXTag, {\n      name: \"inlineCode\",\n      components: components,\n      parentName: \"p\"\n    }, `setOn`), ` closure on `, React.createElement(MDXTag, {\n      name: \"inlineCode\",\n      components: components,\n      parentName: \"p\"\n    }, `Model.Item`), ` that receives:`), React.createElement(MDXTag, {\n      name: \"ul\",\n      components: components\n    }, React.createElement(MDXTag, {\n      name: \"li\",\n      components: components,\n      parentName: \"ul\"\n    }, `a `, React.createElement(MDXTag, {\n      name: \"inlineCode\",\n      components: components,\n      parentName: \"li\"\n    }, `Binding`), ` of `, React.createElement(MDXTag, {\n      name: \"inlineCode\",\n      components: components,\n      parentName: \"li\"\n    }, `Model.Item`)), React.createElement(MDXTag, {\n      name: \"li\",\n      components: components,\n      parentName: \"ul\"\n    }, `the new value`)), React.createElement(MDXTag, {\n      name: \"p\",\n      components: components\n    }, `so that we can fill customizable synchronous/asynchronous setter logic in it.`), React.createElement(MDXTag, {\n      name: \"pre\",\n      components: components\n    }, React.createElement(MDXTag, {\n      name: \"code\",\n      components: components,\n      parentName: \"pre\",\n      props: {\n        \"className\": \"language-swift\"\n      }\n    }, `class Model: ObservableObject {\n\n  struct Item {\n    \n    var description: String\n    \n    fileprivate(set) var isOn: Bool\n    \n    var setOn: (_ item: Binding<Item>, _ isOn: Bool) -> Void\n    \n  }\n  \n}\n`)), React.createElement(MDXTag, {\n      name: \"p\",\n      components: components\n    }, `For my colleague's case, we should grab the `, React.createElement(MDXTag, {\n      name: \"inlineCode\",\n      components: components,\n      parentName: \"p\"\n    }, `Binding`), ` of `, React.createElement(MDXTag, {\n      name: \"inlineCode\",\n      components: components,\n      parentName: \"p\"\n    }, `Model.Item`), ` and set the new value to the `, React.createElement(MDXTag, {\n      name: \"inlineCode\",\n      components: components,\n      parentName: \"p\"\n    }, `Binding`), `'s `, React.createElement(MDXTag, {\n      name: \"inlineCode\",\n      components: components,\n      parentName: \"p\"\n    }, `wrappedValue`), ` when the asynchronous setter is completed.`), React.createElement(MDXTag, {\n      name: \"pre\",\n      components: components\n    }, React.createElement(MDXTag, {\n      name: \"code\",\n      components: components,\n      parentName: \"pre\",\n      props: {\n        \"className\": \"language-swift\"\n      }\n    }, `class Model: ObservableObject {\n\n  ...\n\n  @Published\n  var items: [Item] = []\n  \n  init() {\n    items = [\n      Item(\n        description: \"Test\",\n        isOn: LegacyModel.shared.isOn,\n        setOn: { (item, newValue) in\n          LegacyModel.shared.setOn(newValue) { success in\n            guard success else {\n              return\n            }\n            DispatchQueue.main.async {\n              item.wrappedValue.isOn = newValue\n            }\n          }\n        }\n      )\n    ]\n  }\n  \n}\n`)), React.createElement(MDXTag, {\n      name: \"p\",\n      components: components\n    }, React.createElement(MDXTag, {\n      name: \"img\",\n      components: components,\n      parentName: \"p\",\n      props: {\n        \"src\": \"/figure-1-expected-behavior-b48113f518a82b5a37b3552e66d526ee.gif\",\n        \"alt\": \"Qualified Source of Truth Behavior\"\n      }\n    })), React.createElement(MDXTag, {\n      name: \"p\",\n      components: components\n    }, `You may have spotted that there is no invocation of `, React.createElement(MDXTag, {\n      name: \"inlineCode\",\n      components: components,\n      parentName: \"p\"\n    }, `self.objectWillChange.send()`), ` in this solution. This is because that the `, React.createElement(MDXTag, {\n      name: \"inlineCode\",\n      components: components,\n      parentName: \"p\"\n    }, `Binding`), ` of `, React.createElement(MDXTag, {\n      name: \"inlineCode\",\n      components: components,\n      parentName: \"p\"\n    }, `Model.Item`), ` dominates the changes propagation of `, React.createElement(MDXTag, {\n      name: \"inlineCode\",\n      components: components,\n      parentName: \"p\"\n    }, `@StateObject var model: Model`), ` -- the changes to `, React.createElement(MDXTag, {\n      name: \"inlineCode\",\n      components: components,\n      parentName: \"p\"\n    }, `@StateObject var model: Model`), ` invoke `, React.createElement(MDXTag, {\n      name: \"inlineCode\",\n      components: components,\n      parentName: \"p\"\n    }, `self.objectWillChange.send()`), ` on behalf of you.`), React.createElement(MDXTag, {\n      name: \"h2\",\n      components: components\n    }, `Better Solution? Wait for the Next Post`), React.createElement(MDXTag, {\n      name: \"p\",\n      components: components\n    }, `Even though we have iterated 3 versions of the solution but the final one is still not good enough. We can spot that:`), React.createElement(MDXTag, {\n      name: \"ul\",\n      components: components\n    }, React.createElement(MDXTag, {\n      name: \"li\",\n      components: components,\n      parentName: \"ul\"\n    }, React.createElement(MDXTag, {\n      name: \"p\",\n      components: components,\n      parentName: \"li\"\n    }, `The user interaction of the button-behaved toggle is weird. Some user interactions on `, React.createElement(MDXTag, {\n      name: \"inlineCode\",\n      components: components,\n      parentName: \"p\"\n    }, `Toggle`), ` disappeared in this implementation.`)), React.createElement(MDXTag, {\n      name: \"li\",\n      components: components,\n      parentName: \"ul\"\n    }, React.createElement(MDXTag, {\n      name: \"p\",\n      components: components,\n      parentName: \"li\"\n    }, `The `, React.createElement(MDXTag, {\n      name: \"inlineCode\",\n      components: components,\n      parentName: \"p\"\n    }, `Toggle`), `'s toggle-off animation begins after the asynchronous setter is completed which means that users may wait for the toggle-off animation to happen before moving their focus away from the `, React.createElement(MDXTag, {\n      name: \"inlineCode\",\n      components: components,\n      parentName: \"p\"\n    }, `Toggle`), ` -- this is not a good design for things that are going out of the user's attraction. It could be better if the `, React.createElement(MDXTag, {\n      name: \"inlineCode\",\n      components: components,\n      parentName: \"p\"\n    }, `Toggle`), ` can be toggled off immediately and reset to toggled on when failure happens.`)), React.createElement(MDXTag, {\n      name: \"li\",\n      components: components,\n      parentName: \"ul\"\n    }, React.createElement(MDXTag, {\n      name: \"p\",\n      components: components,\n      parentName: \"li\"\n    }, `We have to hand-wire the asynchronous set logic in `, React.createElement(MDXTag, {\n      name: \"inlineCode\",\n      components: components,\n      parentName: \"p\"\n    }, `Item.Model.setOn`), `. This is error-prone;`)), React.createElement(MDXTag, {\n      name: \"li\",\n      components: components,\n      parentName: \"ul\"\n    }, React.createElement(MDXTag, {\n      name: \"p\",\n      components: components,\n      parentName: \"li\"\n    }, `What if there is a reference semantics model that offers an asynchronous getter? How do we deal with it?`)), React.createElement(MDXTag, {\n      name: \"li\",\n      components: components,\n      parentName: \"ul\"\n    }, React.createElement(MDXTag, {\n      name: \"p\",\n      components: components,\n      parentName: \"li\"\n    }, `What if the asynchronous access can be failed? How do we deal with it?`)), React.createElement(MDXTag, {\n      name: \"li\",\n      components: components,\n      parentName: \"ul\"\n    }, React.createElement(MDXTag, {\n      name: \"p\",\n      components: components,\n      parentName: \"li\"\n    }, `There is boilerplate code in the `, React.createElement(MDXTag, {\n      name: \"inlineCode\",\n      components: components,\n      parentName: \"p\"\n    }, `action`), ` closure of the `, React.createElement(MDXTag, {\n      name: \"inlineCode\",\n      components: components,\n      parentName: \"p\"\n    }, `Button`), ` in the `, React.createElement(MDXTag, {\n      name: \"inlineCode\",\n      components: components,\n      parentName: \"p\"\n    }, `ItemView`), `.`))), React.createElement(MDXTag, {\n      name: \"p\",\n      components: components\n    }, `On the other hand, real-world reference semantics models may come with:`), React.createElement(MDXTag, {\n      name: \"ul\",\n      components: components\n    }, React.createElement(MDXTag, {\n      name: \"li\",\n      components: components,\n      parentName: \"ul\"\n    }, React.createElement(MDXTag, {\n      name: \"p\",\n      components: components,\n      parentName: \"li\"\n    }, `Only the getter method and no setter method`)), React.createElement(MDXTag, {\n      name: \"li\",\n      components: components,\n      parentName: \"ul\"\n    }, React.createElement(MDXTag, {\n      name: \"p\",\n      components: components,\n      parentName: \"li\"\n    }, `Only the setter method and no getter method`)), React.createElement(MDXTag, {\n      name: \"li\",\n      components: components,\n      parentName: \"ul\"\n    }, React.createElement(MDXTag, {\n      name: \"p\",\n      components: components,\n      parentName: \"li\"\n    }, `May be modified outside SwiftUI without any notifications`))), React.createElement(MDXTag, {\n      name: \"p\",\n      components: components\n    }, `To deal with reference semantics models like this, we have to write additional codes to get a source of truth in SwiftUI work.`), React.createElement(MDXTag, {\n      name: \"p\",\n      components: components\n    }, `To keep this post concise and focused, all the points mentioned above would be tackled in the following posts.`), React.createElement(MDXTag, {\n      name: \"h2\",\n      components: components\n    }, `Conclusions`), React.createElement(MDXTag, {\n      name: \"p\",\n      components: components\n    }, `In this post, I've shown you that:`), React.createElement(MDXTag, {\n      name: \"ul\",\n      components: components\n    }, React.createElement(MDXTag, {\n      name: \"li\",\n      components: components,\n      parentName: \"ul\"\n    }, React.createElement(MDXTag, {\n      name: \"p\",\n      components: components,\n      parentName: \"li\"\n    }, `The source of truth in SwiftUI are dynamic properties that can project `, React.createElement(MDXTag, {\n      name: \"inlineCode\",\n      components: components,\n      parentName: \"p\"\n    }, `Binding`), `s.`)), React.createElement(MDXTag, {\n      name: \"li\",\n      components: components,\n      parentName: \"ul\"\n    }, React.createElement(MDXTag, {\n      name: \"p\",\n      components: components,\n      parentName: \"li\"\n    }, `To compose a qualified source of truth, we have to directly install the dynamic properties on `, React.createElement(MDXTag, {\n      name: \"inlineCode\",\n      components: components,\n      parentName: \"p\"\n    }, `View`), `, `, React.createElement(MDXTag, {\n      name: \"inlineCode\",\n      components: components,\n      parentName: \"p\"\n    }, `Gesture`), ` or other structural user interface types shipped with SwiftUI`)), React.createElement(MDXTag, {\n      name: \"li\",\n      components: components,\n      parentName: \"ul\"\n    }, React.createElement(MDXTag, {\n      name: \"p\",\n      components: components,\n      parentName: \"li\"\n    }, `With the help of `, React.createElement(MDXTag, {\n      name: \"inlineCode\",\n      components: components,\n      parentName: \"p\"\n    }, `Binding`), `, we can naïvely deal with asynchronous methods in SwiftUI.`))));\n  }\n\n}\nMDXContent.isMDXComponent = true;","scope":""},"headings":[{"value":"Introduction","depth":2},{"value":"The Initial Problem","depth":2},{"value":"Hack 1: What Drives SwiftUI's Updates?","depth":2},{"value":"Hack 2: Understanding Dynamic Property Update","depth":2},{"value":"A Deeper Understanding of Binding","depth":3},{"value":"Make a Hack That Works","depth":3},{"value":"Suggested Solution: Compose a Qualified Source of Truth","depth":2},{"value":"Better Solution? Wait for the Next Post","depth":2},{"value":"Conclusions","depth":2}]}}},"earlierPostExcerpt":{"slug":"/post/2023/01/a-study-of-llvm-adt-ilist-iplist-and-simple-ilist-938d","title":"A Study of LLVM ADT: ilist, iplist and simple_ilist","subtitle":"","createdTime":"2023-01-15T00:00:00.000Z","tags":["LLVM","ADT","C++"],"category":"Programming","file":{"childMdx":{"excerpt":"Introduction ilist  is an intrusive double-linked list -- which means that each linked node stores its data and the node pointers in the same structure. There is no such kind of linked-list implemented containers shipped with the C++ standard library. iplist  is a purely intrusive list. Currently…"}}},"laterPostExcerpt":{"slug":"/post/2023/08/swift-macro-revisited-the-strengths-and-essence-a5a4","title":"Swift Macro: Revisited - The Strengths and Essence","subtitle":"","createdTime":"2023-08-08T00:00:00.000Z","tags":["Swift","Macro"],"category":"Programming","file":{"childMdx":{"excerpt":"From the sessions at WWDC 2023, we learned that Swift Macro aims to: Eliminate boilerplates Make tedious things easy Share with other developers in packages However, these goals aren't unique to Swift Macro. They are common\nobjectives for many code reuse methods in Swift, such as functions, types…"}}}},"pageContext":{"postId":"e508707d-f31e-5d24-b1ac-2b6a1b6155fc","earlierPostId":"644e5f5d-bcdf-5700-9877-34088a7af8e8","laterPostId":"f2b372f7-8c6e-5cc2-9792-84dc1fac5aa9"}}