如果我理解你的问题正确,你认为
@IBOutlet
属性应该始终标记为
private
...好吧,这不是真的。但直接访问属性也不安全。你知道ViewControllers、TableViewCells和这些对象在可选的IBOutlets上使用隐式展开的原因...当你使用storyboards或仅在代码中的某个地方使用它们时,你不需要初始化ViewController...另一种方式 - 想象一下你正在以编程方式创建VC,并将所有标签传递给初始化程序...这会让你头脑爆炸...相反,在storyboard中,你可以这样做:
@IBOutlet var myLabel: UILabel!
这很酷,你不需要在init中设置它,它只会等待在访问其值之前的某个时间点被设置...界面构建器会在ViewDidLoad之前处理初始化,所以标签在此之后不会为nil...再次在
AwakeFromNib
方法进入UITableViewCell子类之前,当你尝试访问你的
bookTitle
标签属性时,它会崩溃,因为它将为空...这就是为什么这应该是私有的棘手部分...否则,当你知道VC 100%在场景中分配时,没有必要害羞并使一切都是私有的...例如,在
prepare(for segue:)
方法中工作时,你绝不能访问@IBOutlets。因为它们没有分配,即使它们被分配了,它们也会被一些推送/呈现/其他函数中的内部调用覆盖...好了,那现在该怎么办?当使用
UITableViewCell
子类时,你可以安全地访问IBOutlets(仅当你使用storyboard并且单元格在你的TableView中❗️),并更改它们的值...
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
guard let cell = tableView.dequeueReusableCell(withIdentifier: "bookTableViewCell", for: indexPath) else { return UITableViewCell() }
cell.bookTitle.text = "any given text"
}
上述案例应该适用于MVC模式,而不是MVVM或其他模式,其中您不使用storyboard与tableViewControllers和嵌入式单元格太多……(由于注册单元格,但这是另一篇文章……)
我将给你一些指针,如何设置单元格/ViewController中的值,而不触摸实际值,并使其安全……还有一个良好的实践(安全)是使IBOutlets是可选的,以达到100%的安全性,但这并非必要,说实话,这将是解决这个问题的奇怪方法:
ViewControllers:
class SomeVC: UIViewController {
@IBOutlet var titleLabel: UILabel?
@IBOutlet var subtitleLabel: UILabel?
var myCustomTitle: String?
var myCustomSubtitle: String?
func setup(with dataSource: SomeVCDataSource ) {
guard let titleLabel = titleLabel, let subtitleLabel = subtitleLabel else { return }
titleLabel.text = dataSource.title
subtitleLabel.text = dataSource.subtitle
}
override func viewDidLoad() {
super.viewDidLoad()
titleLabel.text = myCustomTitle
subtitleLabel.text = myCustomSubtitle
}
}
struct SomeVCDataSource {
var title: String
var subtitle: String
}
下一个问题可能是这样的:
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
guard let destinationVC = segue.destination as? SomeVC else { return }
let datasource = SomeVCDataSource(title: "Foo", subtitle: "Bar")
destinationVC.setup(with: datasource)
destinationVC.myCustomTitle = "Foo"
destinationVC.myCustomSubtitle = "Bar"
}
你知道的,你不需要将你的IBOutlets设置为私有的,因为你永远不知道你将如何使用它们。如果你需要更多例子或有什么不清楚的地方,请随时问...祝你编码愉快,学习深入!