0

I want to call the callback function from native code:

From header:

void load_all(Client *client,
                         void (*cb_result)(const ResponseWrapper*),
                         void (*cb_error)(char*));

This is my callback in Swift:

 let result: @convention(c) (UnsafePointer<ResponseWrapper>?) -> Void = { pointer in
      if let ResponseWrapper = pointer?.pointee {
        print("data \(data.length)")
      }
    }

When I try to return results from result callback to swift I got next error:

A C function pointer cannot be formed from a closure that captures context

What is the best way to overcome this limitation?

Is the only way to save an instance of my class to a pointer, send to native code and cast back to object?

let owner = UnsafeMutableRawPointer(Unmanaged.passRetained(callbackWrapper).toOpaque())
let owner: Response = Unmanaged.fromOpaque($0!).takeUnretainedValue()

This is not working as well:

func loadAll() {

    //Loader class
    let ownedPointer = UnsafeMutableRawPointer(Unmanaged.passUnretained(self).toOpaque())

    let result: @convention(c) (UnsafePointer<ResponseWrapper>?) -> Void = { pointer in
      if let ResponseWrapper = pointer?.pointee {
        print("data \(data.length)")
      }
      let newSelf:Loader = Unmanaged.fromOpaque(ownedPointer).takeUnretainedValue()
    }
}

My current solution:

  • Swift : gist.github.com/xajik/fe360b705f63ceba4a71f94d1ce2dc41
  • Rust: gist.github.com/xajik/8b532c44e3a267a5d8ae450ea11ad41c
ilbets
  • 710
  • 1
  • 9
  • 35
  • Did you have a look at [How to use instance method as callback for function which takes only func or literal closure](https://stackoverflow.com/questions/33260808/how-to-use-instance-method-as-callback-for-function-which-takes-only-func-or-lit) ? – Martin R May 05 '20 at 08:43
  • 2
    *"Is the only way to save an instance of my class to a pointer, send to native code and cast back to object?"* – Yes. – Martin R May 05 '20 at 08:48
  • What if it, not my library and I cannot modify it? There is no way to get data? – ilbets May 05 '20 at 08:51
  • But you have to take care of the reference counting. With `passRetained()` you keep the instance alive, but must release it eventually to avoid a memory leak. With `passUnretained()` you must ensure that the instance is alive as long as the callback is active. – Martin R May 05 '20 at 08:52
  • Understood. So if I cannot modify the source code of the library I can not to anything here? – ilbets May 05 '20 at 09:11
  • I am not sure if I understand what you mean. All the pointer juggling is done on the Swift side, not in the C library. – Martin R May 05 '20 at 09:21
  • I added one more example, please check – ilbets May 05 '20 at 09:59
  • How does it “not work”? What is ResponseWrapper? Please post a [mcve]. – Martin R May 05 '20 at 10:47
  • Here `self ` and `ResponseWrapper ` are different object. Based on the link you shared first I need to send `self` to native code and return to the callback with `ResponseWrapper` - I managed to make it work like that. So my questions is there any possible hack to avoid this? – ilbets May 05 '20 at 14:22
  • I created a gist to explain it better: Swift : https://gist.github.com/xajik/fe360b705f63ceba4a71f94d1ce2dc41 Rust: https://gist.github.com/xajik/8b532c44e3a267a5d8ae450ea11ad41c – ilbets May 07 '20 at 06:43

0 Answers0