简体   繁体   中英

How do I pass in a void block to objc_setAssociatedObject in swift

I'm trying to add tap gesture support to UIView via an extension. This is pretty straight forward using Objective-C, but I'm getting the following error when trying to set the void return block on the runtime property.

error: type '() -> Void' does not conform to protocol 'AnyObject'

Here is the computed property:

var tapAction: (() -> Void)? {

    get {
        objc_getAssociatedObject(self, &AssociatedKeys.SNGLSActionHandlerTapBlockKey)
    }

    set {

        objc_setAssociatedObject(
            self,
            &AssociatedKeys.SNGLSActionHandlerTapBlockKey,
            newValue,
            UInt(OBJC_ASSOCIATION_COPY_NONATOMIC)
        )
    }
}

I've tried to set the tapAction as a typealias , but still receive the same error.

The problem is closures are not objects that conform to AnyObject so you can't store them like that from Swift.

You could look into wrapping the closures in a class with a single property. Something like:

class ClosureWrapper {
  var closure: (() -> Void)?

  init(_ closure: (() -> Void)?) {
    self.closure = closure
  }
}

var tapAction: (() -> Void)? {
  get {
    if let cl = objc_getAssociatedObject(self, "key") as? ClosureWrapper {
      return cl.closure
    }
    return nil
  }

  set {
    objc_setAssociatedObject(
      self,
      "key",
      ClosureWrapper(newValue),
      UInt(OBJC_ASSOCIATION_RETAIN_NONATOMIC)
    )
  }
}

It's a little ugly and could use a nice typealias but it's one way to do it.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM