以下问题发生在 Xcode 16.2、iOS18 SDK 构建目标为 iOS17 的情况下
我有一个扩展UIBarButtonItem
来支持闭包而不是目标/动作:
extension UIBarButtonItem {
typealias Closure = () -> Void
private class UIBarButtonItemClosureWrapper: NSObject {
let closure: Closure
init(_ closure: @escaping Closure) {
self.closure = closure
}
deinit {
print("DEINIT")
}
}
private enum AssociatedKeys {
static var targetClosure = 1
}
convenience init(title: String?, style: UIBarButtonItem.Style, closure: @escaping Closure) {
self.init(title: title, style: style, target: nil, action: #selector(closureAction))
objc_setAssociatedObject(self, &AssociatedKeys.targetClosure, UIBarButtonItemClosureWrapper(closure), objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC)
}
convenience init(image: UIImage?, style: UIBarButtonItem.Style, closure: @escaping Closure) {
self.init(image: image, style: style, target: nil, action: #selector(closureAction))
objc_setAssociatedObject(self, &AssociatedKeys.targetClosure, UIBarButtonItemClosureWrapper(closure), objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC)
}
@objc
func closureAction() {
guard let closureWrapper = objc_getAssociatedObject(self, &AssociatedKeys.targetClosure) as? UIBarButtonItemClosureWrapper else { return }
closureWrapper.closure()
}
}
然而,一些非常奇怪的事情发生了,我不知道为什么。
UIViewController
我在中的a 中使用它navigationItem.rightBarButtonItems
,并且该 viewcontroller 是 的根 viewcontroller UINavigationController
。一切正常,直到我将 添加到包含在该 viewcontroller 的子 viewcontroller 中的TextField
SwiftUI 中。View
UIHostingController
总结一下:
UINavigationController -> UIViewController -> UIHostingController -> TextField
一旦我将焦点放在 上TextField
,按钮就不再起作用。您可以看到它在点击时变得半透明(因此它正在记录点击),但不再调用闭包。如果我将一个使用标准目标/动作系统的按钮放在它旁边,该按钮将继续工作。
这是UIViewController
代码:
override func viewDidLoad() {
super.viewDidLoad()
let item = UIBarButtonItem(title: "TargetAction", style: .done, target: self, action: #selector(buttonTapped))
let item2 = UIBarButtonItem(title: "ClosureAction", style: .done) {
print("CLOSURE TEST")
}
self.navigationItem.rightBarButtonItems = [item, item2]
}
@objc func buttonTapped() {
print("TARGET TEST")
}
这是View
代码:
struct MyView: View {
var body: some View {
Form {
TextField("name", text: .constant("text"))
}
}
Target Test
每次我点击按钮时都会打印。每次Closure Test
我点击另一个按钮时都会打印,直到我通过点击 TextField 来聚焦它。从那时起Target Test
仍然有效,但Closure Test
不再打印。
TextField 的焦点和键盘外观是否会在我不知道的后台对导航栏进行某些操作,从而以某种方式破坏相关对象?Deinit
永远不会打印,并且放置断点ClosureAction
显示该函数也不会被调用。