我知道我们的IBOutlets应该是私有的,但是例如如果我在TableViewCell中有IBOutlets,我应该如何从另一个ViewController访问它们?以下是我提出这类问题的例子:
class BookTableViewCell: UITableViewCell {
@IBOutlet weak private var bookTitle: UILabel!
}
如果我指定IBOutlet它应该私有,我在访问单元格属性时在另一个ViewController中出错:' bookTitle&#39 ;因私人'而无法访问保护等级
答案 0 :(得分:2)
您应该只展示您需要的东西。
例如,您可以set
和get
仅在单元格中使用text
属性。
class BookTableViewCell: UITableViewCell {
@IBOutlet weak private var bookTitleLabel: UILabel!
var bookTitle: String? {
set {
bookTitleLabel.text = newValue
}
get {
return bookTitleLabel.text
}
}
}
然后,无论你需要什么:
cell.bookTitle = "It"
现在,外部对象无法访问bookTitleLabel
,但可以更改其文本内容。
我通常做的是配置方法,它接收数据对象并私下设置它的所有插座功能。
答案 1 :(得分:1)
我看到你对此有点困惑让我为你澄清一下......如果我理解你的问题,你假设@IBOutlet
属性应该被标记为private
所有时间......嗯,这不是真的。但是直接访问这些属性根本不安全。您可以看到ViewControllers,TableViewCells和这些对象在可选的IBOutlets上使用隐式展开...原因是您不需要在使用故事板时初始化ViewController,或者只是在代码中使用它们时...另一种方式 - 想象一下你是以编程方式创建VC并且您将所有标签传递给初始化程序...它会让您大吃一惊...而不是这样,您可以在故事板中使用它:
@IBOutlet var myLabel: UILabel!
这很酷,你不需要在init上使用它,它只是在等待在访问它的值之前在某处设置...接口构建器将在ViewDidLoad之前处理初始化,所以标签在那个时间之后不会是nil ...再次在AwakeFromNib
方法进入UITableViewCell子类之前,当你试图访问你的bookTitle
标签属性时,它会崩溃,因为它将是nil ..关于为什么这应该是私有的,这是一个棘手的部分...否则,当你知道VC在现场100%分配时,没有必要害羞并让一切都变得私密......
当您使用prepare(for segue:)
方法工作时,您不应该访问@IBOutlets。由于它们没有被分配,即使它们是,它们也会被push / present /无论函数中的一些内部调用覆盖......
好的,这很酷..所以现在该怎么办?
使用UITableViewCell
子类时,您可以安全地访问IBOutlets(只有在您使用故事板和细胞在您的TABLEVIEW❗️内)
并改变他们的价值......你看
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
// We shouldn't return just some constructor with UITableViewCell, but who cares for this purposes...
guard let cell = tableView.dequeueReusableCell(withIdentifier: "bookTableViewCell", for: indexPath) else { return UITableViewCell() }
cell.bookTitle.text = "any given text" // This should work ok because of interface builder...
}
以上情况应该适用于MVC模式,而不是MVVM或其他模式,你不使用带有tableViewControllers的故事板并嵌入过多的单元格...(因为注册单元格,但那是其他文章...)
我将为您提供一些指示,如何在不触及实际值的情况下设置单元格/ ViewController中的值并使其安全...同样良好的做法(安全)是使IBOutlets可选为100%安全,但这并不是必要的,老实说,解决这个问题的方法很奇怪:
ViewControllers:
class SomeVC: UIViewController {
// This solution should be effective when those labels could be marked weak too...
// Always access weak variables NOT DIRECTLY but with safe unwrap...
@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 }
// Now the values are safely unwrapped and nothing can crash...
titleLabel.text = dataSource.title
subtitleLabel.text = dataSource.subtitle
}
// WHen using prepare for segue, use this:
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")
// This sets up cool labels... but the labels are Nil before the segue occurs and even after that, so the guard in setup(with dataSource:) will fail and return...
destinationVC.setup(with: datasource)
// So instead of this you should set the properties myCustomTitle and myCustomSubtitle to values you want and then in viewDidLoad set the values
destinationVC.myCustomTitle = "Foo"
destinationVC.myCustomSubtitle = "Bar"
}
你知道,你不需要将你的IBOutlets设置为私人,因为你永远不知道如何使用它们如果你需要更多的例子或者你不清楚的事情,请按你的意愿问...祝你快乐编码深入学习!
答案 2 :(得分:-1)
我还没有让IBOutlets变得私密,至少对于细胞而言。如果您希望这样做,请在单元格中提供一个非私有的配置方法,您可以将值传递给您要分配给您的插座的方法。单元格中的函数可能如下所示:
func configure(with bookTitle: String) {
bookTitle.text = bookTitle
}
编辑:当您更改单元格并添加新插座时,此功能对将来非常有用。然后,您可以向configure
函数添加参数来处理这些参数。您将在任何地方遇到编译器错误,使用该功能,这使您可以在任何使用它的地方正确设置单元格。这对于在不同地方重用单元格的大项目很有帮助。