我的代码已经从Eric Armstrong的代码中稍作修改了>
Adding a closure as target to a UIButton
但是两个代码都有问题。那些来自Eric的人确实删除了
func removeTarget(for controlEvent: UIControl.Event = .touchUpInside)
另一方面,修改后的代码根本无法删除目标动作。当然,这是由于if条件引起的,但这也意味着在Storable属性中没有正确存储目标。
extension UIControl: ExtensionPropertyStorable { class Property: PropertyProvider { static var property = NSMutableDictionary() static func makeProperty() -> NSMutableDictionary? { return NSMutableDictionary() } } func addTarget(for controlEvent: UIControl.Event = .touchUpInside, target: @escaping (_ sender: Any) ->()) { let key = String(describing: controlEvent) let target = Target(target: target) addTarget(target, action: target.action, for: controlEvent) property[key] = target } func removeTarget(for controlEvent: UIControl.Event = .touchUpInside) { let key = String(describing: controlEvent) if let target = property[key] as? Target { removeTarget(target, action: target.action, for: controlEvent) property[key] = nil } } } // Wrapper class for the selector class Target { private let t: (_ sender: Any) -> () init(target t: @escaping (_ sender: Any) -> ()) { self.t = t } @objc private func s(_ sender: Any) { t(sender) } public var action: Selector { return #selector(s(_:)) } } // Protocols with associatedtypes so we can hide the objc_ code protocol PropertyProvider { associatedtype PropertyType: Any static var property: PropertyType { get set } static func makeProperty() -> PropertyType? } extension PropertyProvider { static func makeProperty() -> PropertyType? { return nil } } protocol ExtensionPropertyStorable: class { associatedtype Property: PropertyProvider } // Extension to make the property default and available extension ExtensionPropertyStorable { typealias Storable = Property.PropertyType var property: Storable { get { let key = String(describing: type(of: Storable.self)) guard let obj = objc_getAssociatedObject(self, key) as? Storable else { if let property = Property.makeProperty() { objc_setAssociatedObject(self, key, property, .OBJC_ASSOCIATION_RETAIN) } return objc_getAssociatedObject(self, key) as? Storable ?? Property.property } return obj } set { let key = String(describing: type(of: Storable.self)) return objc_setAssociatedObject(self, key, newValue, .OBJC_ASSOCIATION_RETAIN) } } }
我的目标是通过闭包精确地注册目标动作并删除它们,而不删除通过#selector添加到给定UITextField的所有其他目标动作。现在,当使用这种方法进行闭合样式的目标动作时,我可以删除目标动作的全部或全部。
更新
基于Eric Armstrong
的答案,我已经实现了我的版本。但是我在Eric提出的版本中所经历的是,当在单元格出现时将目标动作添加到TableView列表上的TextField上,然后在单元格消失时从文本字段中删除此目标动作,而先前的代码似乎删除了removeTarget(for:)
执行中的所有目标动作。因此,当在诸如UITableViewCell之类的代码中的其他位置,我在单元格消失后又在完全不同的目标(UITableViewCell对象,而不是此自定义Target()对象)上添加了其他目标动作,然后再次出现在屏幕上并执行了removeTarget(for),然后执行此操作其他(我称之为目标操作外部)也已删除,再也没有调用。 [我认为某个问题是[String:Target]字典的使用,该字典是值类型,在objc_getAssociatedObject中存在属性的getter的情况下使用过
objc_getAssociatedObject(self, key) as? Storable ?? Property.property
据我所知,然后没有给定键的objc对象,并且Storable为nil,并且调用了nil-coalescing运算符,并且静态值类型Property.property返回aka [String:Dictionary]
因此它由副本返回,并且目标对象存储在此复制的对象中,该对象并非永久存储并在removeTarget(for :)中访问,始终为nil。因此,将nil传递给UIControl.removetTarget(),并且始终清除所有目标操作!
[我尝试用NSMutableDictionary简单地将[String:Target] Swift字典替换为引用类型,所以我认为可以存储它。但是这种对静态变量的简单替换,只是通过nil-coalesing运算符将其返回,这是因为我假设目标对象只有一个这样的存储,然后在滚动表视图时,每个removeForTarget()都会以某种方式从所有UITextFields中删除所有目标操作,而不是仅从当前开始。
我还认为String(describing:type(of:Storable.self))的用法是错误的,因为对于给定的Storable类型它将始终相同。
我对Eric Armstrong的代码做了一些修改,为UIButton添加了一个闭包作为目标,但是这两个代码都有问题。那些来自Eric的人确实删除了...
好,我想我终于解决了这个问题