私人 IB 网点 Swift
Private IBOutlets Swift
我知道我们的 IBOutlets 应该是私有的,但是例如,如果我在 TableViewCell 中有 IBOutlets,我应该如何从另一个 ViewController 访问它们?这是我问这种问题的例子:
class BookTableViewCell: UITableViewCell {
@IBOutlet weak private var bookTitle: UILabel!
}
如果我分配给 IBOutlet 它应该是 private,我在访问单元格 属性 时在另一个 ViewController 中出错: 由于 'private' 保护级别
,'bookTitle' 无法访问
我还没有遇到过让 IBOutlets 私有化变得普遍,至少对于单元格而言。如果你想这样做,请在你的单元格中提供一个非私有的配置方法,你可以将值传递给它,你想分配给你的网点。您的单元格中的函数可能如下所示:
func configure(with bookTitle: String) {
bookTitle.text = bookTitle
}
编辑:当您更改电池并添加新插座时,这样的功能对将来很有用。然后,您可以将参数添加到 configure
函数来处理这些问题。您将在任何地方遇到编译器错误,在您使用该函数的地方,这使您可以在任何使用它的地方正确设置您的单元格。这对于在不同地方重用单元格的大型项目很有帮助。
您应该只公开您需要的内容。
例如,您可以 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
但可以更改其文本内容。
我通常做的是接收数据对象并私下设置其所有出口功能的配置方法。
如果我对您的问题的理解正确,您是在假设 @IBOutlet
属性应该始终标记为 private
……但事实并非如此。但也直接访问属性根本不安全。您会看到 ViewControllers、TableViewCells 和这些对象出于某种原因在可选的 IBOutlets 上使用隐式解包...您不需要在使用故事板或仅在代码中的某处使用它们时初始化 ViewController。 . 另一种方式 - 想象一下你正在以编程方式创建 VC 并且你正在将所有标签传递给初始化程序......它会让你大吃一惊......而不是这个,你在故事板中使用这个:
@IBOutlet var myLabel: UILabel!
这很酷,您不需要在 init 上拥有它,它会在那里等待在访问它的值之前在某个地方设置...Interface builder 将在 ViewDidLoad 之前为您处理初始化,所以在那之后标签不会为零...再次在 AwakeFromNib
方法进入 UITableViewCell 子类之前,当您尝试访问您的 bookTitle
标签 属性 时,它会崩溃,因为它将为零...这是关于为什么这应该是私有的棘手部分...否则当您知道 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 或其他模式,在这些模式中,您不使用带表 ViewController 的情节提要和过多嵌入单元格...(因为注册单元格,但那是另一篇文章...)
我会给你一些建议,如何在不触及实际值的情况下设置 cell/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 设置为私有,因为你永远不知道你将如何使用它们快乐的编码和深度学习!
我知道我们的 IBOutlets 应该是私有的,但是例如,如果我在 TableViewCell 中有 IBOutlets,我应该如何从另一个 ViewController 访问它们?这是我问这种问题的例子:
class BookTableViewCell: UITableViewCell {
@IBOutlet weak private var bookTitle: UILabel!
}
如果我分配给 IBOutlet 它应该是 private,我在访问单元格 属性 时在另一个 ViewController 中出错: 由于 'private' 保护级别
,'bookTitle' 无法访问我还没有遇到过让 IBOutlets 私有化变得普遍,至少对于单元格而言。如果你想这样做,请在你的单元格中提供一个非私有的配置方法,你可以将值传递给它,你想分配给你的网点。您的单元格中的函数可能如下所示:
func configure(with bookTitle: String) {
bookTitle.text = bookTitle
}
编辑:当您更改电池并添加新插座时,这样的功能对将来很有用。然后,您可以将参数添加到 configure
函数来处理这些问题。您将在任何地方遇到编译器错误,在您使用该函数的地方,这使您可以在任何使用它的地方正确设置您的单元格。这对于在不同地方重用单元格的大型项目很有帮助。
您应该只公开您需要的内容。
例如,您可以 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
但可以更改其文本内容。
我通常做的是接收数据对象并私下设置其所有出口功能的配置方法。
如果我对您的问题的理解正确,您是在假设 @IBOutlet
属性应该始终标记为 private
……但事实并非如此。但也直接访问属性根本不安全。您会看到 ViewControllers、TableViewCells 和这些对象出于某种原因在可选的 IBOutlets 上使用隐式解包...您不需要在使用故事板或仅在代码中的某处使用它们时初始化 ViewController。 . 另一种方式 - 想象一下你正在以编程方式创建 VC 并且你正在将所有标签传递给初始化程序......它会让你大吃一惊......而不是这个,你在故事板中使用这个:
@IBOutlet var myLabel: UILabel!
这很酷,您不需要在 init 上拥有它,它会在那里等待在访问它的值之前在某个地方设置...Interface builder 将在 ViewDidLoad 之前为您处理初始化,所以在那之后标签不会为零...再次在 AwakeFromNib
方法进入 UITableViewCell 子类之前,当您尝试访问您的 bookTitle
标签 属性 时,它会崩溃,因为它将为零...这是关于为什么这应该是私有的棘手部分...否则当您知道 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 或其他模式,在这些模式中,您不使用带表 ViewController 的情节提要和过多嵌入单元格...(因为注册单元格,但那是另一篇文章...)
我会给你一些建议,如何在不触及实际值的情况下设置 cell/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 设置为私有,因为你永远不知道你将如何使用它们快乐的编码和深度学习!