У меня есть такой код, немного измененный по сравнению с кодом Эрик Армстронг
Добавление замыкания в качестве цели для кнопки UIB
Но естьпроблема с обоими кодами. Те из Эрика действительно удаляют все целевые действия на
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) }
}
}
Моя цель - точно зарегистрировать целевые действия с замыканиями и удалить их, не удаляя все другие целевые действия, добавленные к данному UITextField через #selector. Теперь я могу удалить ВСЕ или НЕТ целевых действий, используя этот подход для целевых действий в стиле замыкания.
ОБНОВЛЕНИЕ
Основано на ответе Эрик Армстронг Я реализовал свою версию. Но что я испытал в версии, предложенной Эриком, так это то, что при добавлении целевых действий в TextField в списке TableView, когда появляются ячейки, а затем при удалении этих целевых действий из текстовых полей, когда ячейки исчезают, предыдущий код, похоже, удаляет все целевые действия при removeTarget(for:)
exection,Поэтому, когда в другом месте в коде, таком как UITableViewCell, я добавил дополнительное целевое действие на совершенно другую цель (объект UITableViewCell, а не этот пользовательский объект Target ()), когда ячейки исчезали, а затем снова появлялись на экране, и затем выполнялся removeTarget (for)другие (внешние, как я их называю, целевые действия) также были удалены и больше никогда не вызывались.
Я считаю, что проблемой было использование словаря [String: Target], который является типом значения, и он использовался в случае получения свойства в objc_getAssociatedObject, где было
objc_getAssociatedObject(self, key) as? Storable ?? Property.property
Так как японять это тогда не было объекта objc для данного ключа и Storable был nil и был вызван оператор nil-coalescing и тип статического значения Property.property return aka [String: Dictionary]
Таким образом, он был возвращен копией иЦелевой объект был сохранен в этом скопированном объекте, который не был постоянно сохранен и доступен в removeTarget (для :) всегда как nil. Таким образом, ноль был передан в UIControl.removetTarget (), и все целевые действия всегда очищались!
Я попытался просто заменить словарь [String: Target] Swift на NSMutableDictionary, который является ссылочным типом, поэтому я предполагаю, что он может быть сохранен. Но эта простая замена статической переменной и просто возвращение ее через оператор nil-coalesing привела к тому, что я предполагаю, что существует только одно такое хранилище для объектов Target, а затем при прокрутке табличного представления каждый removeForTarget () каким-то образом удаляет все целевые действия из всех UITextFields, но нетолько из текущих.
Я также считаю использование String (описывающего: type (of: Storable.self)) неправильным, так как оно всегда будет одинаковым для данного типа Storable.