Swift UITextField 目标操作作为闭包,不删除目标操作的问题



我从埃里克·阿姆斯特朗的代码中稍微修改了这样的代码

将闭包作为目标添加到 UIButton

但是这两个代码都存在问题。来自埃里克的那些确实删除了所有目标操作

func removeTarget(for controlEvent: UIControl.Event = .touchUpInside)

另一方面,修改后的代码根本不会删除目标操作。当然,这是由 if 条件引起的,但这也意味着在可存储属性中没有正确存储的目标。

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 提出的版本中所经历的是,当在单元格出现时将目标操作添加到 TableView 列表上的 TextField 时,然后在单元格消失时从文本字段中删除此目标操作,以前的代码似乎删除了removeTarget(for:)执行的所有目标操作。因此,当在UITableViewCell等代码中的其他地方时,我在完全不同的目标(UITableViewCell对象,而不是这个自定义Target((对象(上添加了额外的目标操作,而单元格消失然后再次出现在屏幕上并执行了removeTarget(for(,然后这个另一个(外部,因为我称之为目标操作(也被删除并且再也没有调用过。

我认为一些问题是使用[字符串:目标]字典,它是值类型,并且在objc_getAssociatedObject有属性的情况下使用它

objc_getAssociatedObject(self, key) as? Storable ?? Property.property

所以据我了解,给定键没有 objc 对象,Storable 为 nil,调用了 nil-coalescing 运算符,静态值类型 Property.property 返回又名 [字符串:字典]

所以它是由复制返回的,目标对象存储在这个复制的对象中,该对象不会永久存储和访问 removeTarget(for:( 始终为 nil。所以nil被传递给UIControl.removetTarget((,所有目标操作总是被清除!。

我已经尝试将[字符串:目标] Swift字典替换为NSMutableDictionary,这是一种引用类型,因此我认为它可以存储。但是这个静态变量的简单替换,只是通过 nil-coalesing 运算符返回它,因为我假设目标对象只有一个这样的存储,然后在滚动表视图时,每个 removeForTarget(( 以某种方式从所有 UITextFields 中删除了所有目标操作,而不仅仅是从当前。

我还认为字符串(描述:类型(的:Storable.self((的使用是错误的,因为对于给定的可存储类型,它总是相同的。

好的,我想我终于解决了这个问题

主要问题是使用AssociatedKey!它需要像下面这样完成

https://stackoverflow.com/a/48731142/4415642

所以我最终得到了这样的代码:

import UIKit
/**
* Swift 4.2 for UIControl and UIGestureRecognizer,
* and and remove targets through swift extension
* stored property paradigm.
* https://stackoverflow.com/a/52796515/4415642
**/
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
print("ADDED (ObjectIdentifier(target)), (target.action)")
}
func removeTarget(for controlEvent: UIControl.Event = .touchUpInside) {
let key = String(describing: controlEvent)
if let target = property[key] as? Target {
print("REMOVE (ObjectIdentifier(target)), (target.action)")
removeTarget(target, action: target.action, for: controlEvent)
property[key] = nil
}
}
}
extension UIGestureRecognizer: ExtensionPropertyStorable {
class Property: PropertyProvider {
static var property: Target?
}
func addTarget(target: @escaping (Any) -> ()) {
let target = Target(target: target)
addTarget(target, action: target.action)
property = target
}
func removeTarget() {
let target = property
removeTarget(target, action: target?.action)
property = 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(_:))
}
deinit {
print("Deinit target: (ObjectIdentifier(self))")
}
}
// 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 {
guard let obj = objc_getAssociatedObject(self, &AssociatedKeys.property) as? Storable else {
if let property = Property.makeProperty() {
objc_setAssociatedObject(self, &AssociatedKeys.property, property, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
}
return objc_getAssociatedObject(self, &AssociatedKeys.property) as? Storable ?? Property.property
}
return obj
}
set {
return objc_setAssociatedObject(self, &AssociatedKeys.property, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC) }
}
}
private struct AssociatedKeys {
static var property = "AssociatedKeys.property"
}

相关内容

  • 没有找到相关文章