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

问题描述 投票:0回答:1

我的代码已经从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的人确实删除了...

swift uitextfield swift-protocols target-action
1个回答
1
投票

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

© www.soinside.com 2019 - 2024. All rights reserved.