提问人:bmt22033 提问时间:3/21/2022 更新时间:4/7/2022 访问量:5468
Xcode 13.3 警告:“'self' 指的是方法 '{object}.self',这可能是意外的
Xcode 13.3 warning: "'self' refers to the method '{object}.self', which may be unexpected
问:
我刚刚更新到 Xcode 13.3,我看到了几个新警告的实例,这是我在以前版本的 Xcode 中没有看到的。例如,我有一个名为 LabelAndSwitchTableViewCell 的简单表视图单元格,如下所示:
import UIKit
class LabelAndSwitchTableViewCell: UITableViewCell {
private let label: UILabel = {
let label = UILabel()
label.translatesAutoresizingMaskIntoConstraints = false
return label
}()
private let _switch: UISwitch = {
let _switch = UISwitch()
_switch.translatesAutoresizingMaskIntoConstraints = false
_switch.addTarget(self, action: #selector(didToggleSwitch), for: .valueChanged)
return _switch
}()
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
contentView.addSubview(label)
contentView.addSubview(_switch)
// layout constraints removed for brevity
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
@objc private func didToggleSwitch() {
print("Switch was toggled...")
}
}
正如你所看到的,我正在向交换机添加一个目标,当开关的值发生变化时,我希望被调用:
_switch.addTarget(self, action: #selector(didToggleSwitch), for: .valueChanged)
更新到 Xcode 13.3 后,我现在在这一行上看到一条新警告:
'self' refers to the method 'LabelAndSwitchTableViewCell.self', which may be unexpected
Xcode 建议静音此警告是替换:
_switch.addTarget(self, action: #selector(didToggleSwitch), for: .valueChanged)
...跟。。。
_switch.addTarget(LabelAndSwitchTableViewCell.self, action: #selector(didToggleSwitch), for: .valueChanged)
进行此更改确实会使警告静音,但当我切换开关时,它还会导致应用程序崩溃(无法识别的选择器)。这是那次崩溃的转储:
[app_mockup.LabelAndSwitchTableViewCell didToggleSwitch]: unrecognized selector sent to class 0x1043d86e8
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '+[app_mockup.LabelAndSwitchTableViewCell didToggleSwitch]: unrecognized selector sent to class 0x1043d86e8'
制作该方法将防止崩溃,但我不确定为什么要这样做。我显然可以恢复更改(从返回到只是),但我想知道我是否应该做其他事情来解决这个问题?didToggleSwitch()
static
LabelAndSwitchTableViewCell.self
self
答:
您可以通过将 lets 更改为 lazy var 来修复
private lazy var _switch2: UISwitch = {
let _switch = UISwitch()
_switch.translatesAutoresizingMaskIntoConstraints = false
_switch.addTarget(self, action: #selector(didToggleSwitch), for: .valueChanged)
return _switch
}()
Xcode 修复建议是错误的。
评论
原因是在对象初始化的第 1 阶段尚未准备就绪。第 1 阶段是设置所有存储的属性,只有在第 2 阶段,您才能访问 .self
self
若要修复代码,可以使用属性,其中初始化阶段 1 已完成。lazy
以下是参考资料:https://docs.swift.org/swift-book/LanguageGuide/Initialization.html
对于此警告:
- 如果没有超类,或者没有超类,则在直接在存储属性中使用时会出现错误。
NSObject
self
- 如果超类是 ,则编译为自动闭包。因此,在运行时,self 将用作当前实例。但是,由于 Swift 5.6 警告我们这一点,我认为在未来的 swift 版本中可能不允许在 NSObject 子类的存储属性中引用 self。
NSObject
self
(ClassXXX) -> () -> ClassXXX
示例 2:AST 中编译的 self
对于此代码:
import Foundation
class MyTest: NSObject {
var myself = self
}
评论
NSObject
self
(ClassXXX) -> () -> ClassXXX
self
self
self
NSObject
LabelAndSwitchTableViewCell.self 在大多数情况下不起作用。使用 nil 并搜索响应程序链。
评论