0

I want make a function which make my typing easier when I must initialize a Binding in some cases!

Here is the code:

func bindingFunction(value: inout CGFloat) -> Binding<CGFloat> {
    return Binding(get: { return value }, set: { newValue in value = newValue })
}

I am getting 2 errors from xCode:

  1. Parameter 'value' is declared 'inout'

Escaping closure captures 'inout' parameter 'value'

My Goal is to solve those errors in first place and finally I want make my function be generic as well, as you see my function works for Binding CGFloat which I want make it generic and then I could use it when I need Binding Bool as well.

ios coder
  • 1
  • 4
  • 31
  • 91
  • 1
    Relevant info as to why `inout` doesn't work here: https://stackoverflow.com/a/39572470/560942 – jnpdx Nov 19 '21 at 01:16
  • So my goal is not possible then, right? – ios coder Nov 19 '21 at 01:17
  • If one of your requirements is that you use `inout`, it seems unlikely (although maybe someone knows some crazy trick to get it to work). You could probably make it work by taking an escaping closure as a parameter that returns the value instead of an `inout` parameter, but at that point, there's really no reason to not just write the Binding in the first place. – jnpdx Nov 19 '21 at 01:19
  • As I said for typing matter it would better. – ios coder Nov 19 '21 at 01:21
  • 2
    But if you used closures, you would need to provide two closures -- one to get and one to set the value, which is exactly what a Binding does in the first place. So, it doesn't save you anything. – jnpdx Nov 19 '21 at 01:24
  • Oh, I see it now! thanks – ios coder Nov 19 '21 at 01:25
  • Please show an example of context where/how do you want to use this. – Asperi Nov 19 '21 at 06:52
  • The place that need binding, for example a view that need a binding of cgfloat to work. @Asperi – ios coder Nov 19 '21 at 08:53

1 Answers1

0

As you've seen in your comments, there's not a good general solution for this. You can really only make it easier if you have a ReferenceWritableKeyPath to work with (which means no value types, such as your CGFloat).

Generally, nobody needs this, because we're all using ObservableObjects + @Published instead.

final class Model {
  var leaves = ""
}

let model = Model()
let fallenLeaves = ""
@Binding(model, keyPath: \.leaves) var leaves;
leaves = fallenLeaves
XCTAssertEqual(model.leaves, fallenLeaves)
public extension Binding {
  init(
    accessors: (
      get: () -> Value,
      set: (Value) -> Void
    )
  ) {
    self.init(get: accessors.get, set: accessors.set)
  }

  init<Root>(
    _ root: Root,
    keyPath: ReferenceWritableKeyPath<Root, Value>
  ) {
    self.init(accessors: keyPath.accessors(root))
  }
}
public extension ReferenceWritableKeyPath {
  /// Partially-applied `get` and `set` accessors for this key path.
  ///
  /// Typical usage: `accessors(root)`
  var accessors: (Root) -> (
    get: () -> Value,
    set: (Value) -> Void
  ) {
    { root in
      ( get: { root[keyPath: self] },
        set: { root[keyPath: self] = $0 }
      )
    }
  }
}
  • Thanks for your time, as I tried to use your given code, it is more look like I should feed 2 closure to it to start working, however I could not use it. So I could do same thing with original Binding initialization for get and set! where could your code be useful? In my question also in my code, I tried at least make the typing part shorter and easier than original Binding. – ios coder Nov 19 '21 at 03:20
  • 1
    Okay, I will try again thanks. – ios coder Nov 19 '21 at 03:53
  • I looked again to XCTest example, I think it need class or a custom class to work, since my code or function require no class, I cannot take advantage of your answer, but thanks for your help. – ios coder Nov 19 '21 at 14:35
  • That is correct. I've added a parenthetical. –  Nov 19 '21 at 16:45