动态定义的函数类型变量

时间:2016-04-07 19:40:07

标签: ios swift swift2

我正在尝试通过创建一个新函数和一个新的Function-type变量来扩展一个UIKit类(我无法正常编辑),它将使用ObjC Runtime使它看起来和感觉像一个储存财产。

extension UITextField {

    private struct DynamicallyDefinedVars {
        static var oneVar = "oneVar"
    }

    var oneVar: ((String?)->Bool)? {
        get{
            return objc_getAssociatedObject(self, &DynamicallyDefinedVars.oneVar) as? (String?)->Bool
        }
        set{
            if let newValue: AnyObject = newValue {
                objc_setAssociatedObject(self, &DynamicallyDefinedVars.oneVar, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
            }
        }
    }

    func callTheVarFunc() -> Bool {
        if let oneVar = oneVar {
            return oneVar("Foo")
        }

        return true
    }
}

我希望实现的目标:

var foo: UITextField

foo.oneVar = { (bar: String?) -> Bool in
  return true
}

if foo.callTheVarFunc {
  doSomething
}

但是我收到以下错误:

Cannot convert value of type '((String?) -> Bool)?' to specified type 'AnyObject?'

如果oneVar被输入类似String或类型的数组,它会正常工作,但我看到AnyObject中没有包含函数类型,因此在尝试objc_setAssociatedObject时给出了问题。有关如何获得所需行为的任​​何想法(通过扩展,没有子类化)?每个实例必须具有不同的oneVar值以与callTheVarFunc函数一起使用。

1 个答案:

答案 0 :(得分:1)

我刚刚看到这个问题,在Swift 闭包中无法投放到 AnyObject ,因此您可以解决这个烦人的事情,创建自定义类:

extension UITextField {

    class CustomClosure {
        var closure: ((String?)->Bool)?

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

    private struct DynamicallyDefinedVars {
        static var oneVar = "oneVar"
    }

    var oneVar: ((String?)->Bool)? {
        get{
            if let cl = objc_getAssociatedObject(self, &DynamicallyDefinedVars.oneVar) as? CustomClosure {
             return cl.closure
            }
        return nil
        }
        set{
            objc_setAssociatedObject(self, &DynamicallyDefinedVars.oneVar,CustomClosure(newValue), .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
        }
    }

    func callTheVarFunc() -> Bool {
        if let oneVar = oneVar {
            return oneVar("Foo")
        }

        return true
    }
}