私人IBOutlets Swift

Lat*_*nec 2 xcode private iboutlet swift

我知道我们的 IBOutlets 应该是私有的,但是例如如果我在 TableViewCell 中有 IBOutlets,我应该如何从另一个 ViewController 访问它们?这是我问这种问题的例子:

class BookTableViewCell: UITableViewCell {

    @IBOutlet weak private var bookTitle: UILabel!

}
Run Code Online (Sandbox Code Playgroud)

如果我分配给 IBOutlet 它应该是私有的,当我访问单元属性时,我在另一个 ViewController 中遇到错误:由于“私有”保护级别,“bookTitle”无法访问

Dan*_*elH 6

您应该只公开您需要的内容。

例如,您只能set使用单元格中的属性。gettext

class BookTableViewCell: UITableViewCell {
    @IBOutlet weak private var bookTitleLabel: UILabel!

    var bookTitle: String? {
        set {
            bookTitleLabel.text = newValue
        }
        get {
            return bookTitleLabel.text
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

然后,无论您需要什么:

cell.bookTitle = "It"
Run Code Online (Sandbox Code Playgroud)

现在外部对象无法访问bookTitleLabel但能够更改其文本内容。

我通常做的是配置方法,该方法接收数据对象并私下设置其所有网点功能。


Dom*_*her 6

如果我正确理解你的问题,你认为@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(仅当您使用 STORYBOARD 并且单元格在您的表格中??)

并改变他们的价值观……你看

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...
}
Run Code Online (Sandbox Code Playgroud)

上面的例子应该在 MVC 模式中工作,而不是 MVVM 或其他模式,你不使用带有 tableViewControllers 的故事板和嵌入单元格......(因为注册单元格,但那是另一篇文章......)

我会给你一些指示,你可以如何在不接触实际值的情况下设置单元格/ViewController 中的值并使其安全......另外一个好的做法(安全)是使 IBOutlets 可选为 100% 安全,但它是没有必要,老实说,这将是解决这个问题的奇怪方法:

视图控制器:

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
}
Run Code Online (Sandbox Code Playgroud)

下一个问题可能是这样的:

    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"
}
Run Code Online (Sandbox Code Playgroud)

你看,你不需要将你的 IBOutlets 设置为私有,因为你永远不知道你将如何使用它们如果你需要更多的例子或者你不清楚的地方,随意提问......祝你编码和深度学习快乐!

  • 我问这个问题是因为出于安全考虑,我想了解是否应该将 IBOutlets 设为私有。一位开发人员退回了我的代码,因为我的 IBOutlet 不是私有的,他告诉我应该使用一种方法,该方法可用于传递数据。如果我这样做,我将避免有人访问单元格并更改任何单元格属性的事实。 (2认同)