首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >私人IBOutlets Swift

私人IBOutlets Swift
EN

Stack Overflow用户
提问于 2017-11-15 14:32:08
回答 3查看 8.6K关注 0票数 5

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

代码语言:javascript
复制
class BookTableViewCell: UITableViewCell {

    @IBOutlet weak private var bookTitle: UILabel!

}

如果我向IBOutlet分配它应该是专用,则在访问单元属性时,在另一个ViewController中出现了一个错误:“bookTitle”由于“私有”保护级别而不可访问

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2017-11-16 00:07:27

如果我正确理解您的问题,您假设@IBOutlet属性应该一直标记为private .这不是真的。但是直接访问属性也是不安全的。您可以看到ViewControllers、TableViewCells和这些对象有理由在可选IBOutlets上使用隐式展开.在使用故事板或只是在代码中的某个地方使用它们时,您不需要插入ViewController .另一种方式--想象一下,你是以编程方式创建VC的,并且将所有标签传递给初始化程序.会打爆你的头..。取而代之的是,您可以在故事板中添加以下内容:

@IBOutlet var myLabel: UILabel!

这很酷,您不需要在init上安装它,它就在那里等待设置,然后访问它的值.接口生成器将在ViewDidLoad之前为您处理初始化,因此标签在此之后不会为零.同样,在AwakeFromNib方法进入UITableViewCell子类之前,当您尝试访问bookTitle label属性时,它会崩溃,因为它将为0.这就是为什么这应该是隐私的棘手部分..。否则,当你知道VC是100%的现场分配,就没有必要害羞,使一切私密.

例如,在使用prepare(for segue:)方法时,不应该访问@IBOutlet。由于它们没有被分配,即使它们被分配了,它们也会被推送/现在/任何函数中的一些内部调用覆盖.

好吧,这很酷..。那现在该怎么办?

使用UITableViewCell子类时,您可以安全地访问IBOutlets (只有在使用情节提要且单元格位于TABLEVIEW❗️中时)

改变他们的价值观..。你看

代码语言:javascript
复制
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中使用情节提要,也不会过多地嵌入单元格。(因为注册了单元格,但这是另一篇文章.)

我将给您一些提示,如何在不触及实际值的情况下在单元格/视图控制器中设置值,并使其安全.此外,良好的实践(安全)是使IBOutlets可选为100%的安全,但这并不是必要的,而且诚实地说,这将是解决这个问题的奇怪方法:

ViewControllers:

代码语言:javascript
复制
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
}

下一个问题可能是:

代码语言:javascript
复制
    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设置为私有,因为您永远不知道您将如何使用它们,如果您需要更多的例子或什么东西是不清楚的,问你想要的……祝你编码愉快,学习深入!

票数 8
EN

Stack Overflow用户

发布于 2017-11-15 14:42:40

你应该只揭露你想要的。

例如,您可以只在单元格中使用setget属性text

代码语言:javascript
复制
class BookTableViewCell: UITableViewCell {
    @IBOutlet weak private var bookTitleLabel: UILabel!

    var bookTitle: String? {
        set {
            bookTitleLabel.text = newValue
        }
        get {
            return bookTitleLabel.text
        }
    }
}

然后,在你需要的地方:

代码语言:javascript
复制
cell.bookTitle = "It"

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

我通常做的是配置方法,它接收数据对象,并私下设置它的所有插座特性。

票数 5
EN

Stack Overflow用户

发布于 2017-11-15 14:36:13

我还没见过让IBOutlets成为私有的东西,至少对于细胞来说是如此。如果要这样做,请在单元内提供一个非私有的配置方法,您可以将值传递给该方法,该方法要分配给您的插座。您的单元内的功能可能如下所示:

代码语言:javascript
复制
func configure(with bookTitle: String) {
    bookTitle.text = bookTitle
}

编辑:当您更改单元格并添加新的出口时,这样的函数可能对将来很有用。然后,可以向configure函数中添加参数以处理这些问题。在使用该函数的任何地方都会出现编译器错误,这使您可以在任何使用该函数的地方正确设置单元格。这对于在不同的地方重用单元格的大型项目是有帮助的。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/47310069

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档