【问题标题】:How to initialize a variable when IBOutlet is initialized?初始化 IBOutlet 时如何初始化变量?
【发布时间】:2019-05-17 03:34:44
【问题描述】:

我碰巧在我的新 iOS Swift 应用程序的UIViewControllers 之一中编写了以下代码 sn-p。

var starButtonsCount = starButtons.count
@IBOutlet var starButtons: [UIButton]!

然后直接在starButtonsCount变量声明旁边出现下面红色的错误。

错误:不能在属性中使用实例成员“starButtons” 初始化器;属性初始化器在“self”可用之前运行。

所以我发现通过将starButtonCount 变量声明为lazy 我们可以解决这个错误(在iOS App 开发过程的长期运行中是暂时的)。

我很想知道解决这个问题的其他方法是什么?

starButtons IBOutlets 初始化时,有没有办法触发starButtonCount 的初始化?

【问题讨论】:

  • 这是awakeFromNib方法的目的。
  • 我在网上搜索时是这么想的。但是找不到具体的答案!您能否进一步详细说明答案?
  • 不声明常量的目的是什么?按钮在设计/编译时连接,因此您应该知道按钮的数量。
  • @vadian 即使我已将starButtonsCount 声明为常量,仍然会出现相同的错误。所以重点应该是如何初始化BOutlets 以及如何捕获它并初始化我的变量。
  • 如果将starButtonsCount 声明为let 并带有常量Int,则不会出现同样的错误

标签: ios swift iboutlet initializer


【解决方案1】:

awakeFromNib 是一个方法,当 .xib 中的每个对象都已反序列化并且所有出口的图形已连接时调用。文档说:

声明

func awakeFromNib()

讨论

从 nib 存档重新创建的每个对象的消息,但仅在之后 存档中的所有对象都已加载并初始化。什么时候 一个对象收到一个 awakeFromNib 消息,它保证有 它的所有出口和动作连接都已经建立。nib 加载基础设施发送一个awakeFromNib

您必须调用 awakeFromNib 的超级实现,以使父类有机会执行它们需要的任何其他初始化。尽管此方法的默认实现什么都不做,但许多UIKit 类提供了非空实现。您可以在自己的awakeFromNib 方法中随时调用超级实现。

如:

class MyUIViewController : UIViewController {
    var starButtonsCount = 0
    @IBOutlet var starButtons: [UIButton]!
    override func awakeFromNib() {
        super.awakeFromNib()
        starButtonsCount = startButtons.count
    }
}

【讨论】:

  • 太好了,如果您也可以提供代码示例的答案会更好! :-)
  • @RandikaVishman 这个代码也可以在viewDidLoad 中设置,所以这里没有新东西要学习
  • @sh_Khan 我认为这有点不正确,因为不仅仅是viewDidLoad 方法,awakeFromNib 直接处理与给定Nib 文件(或在这种情况下为StoryBoard)相关的连接和初始化)。请阅读此答案的文档摘录!
  • @Sh_Khan 当然有很多地方可以放置这样的代码,但是 OP 确实想知道如何捕获已正确设置插座的事实,而这正是 @987654332 的目的@, viewDidLoad 是另一回事。
【解决方案2】:

另一种方式

var starButtonsCount:Int! 
@IBOutlet var starButtons: [UIButton]! { 
    didSet { 
         starButtonsCount = starButtons.count
    }
}

【讨论】:

  • 在这种情况下效果很好,但这并不能让您控制 IBOutlets 的多个/复杂设置...
  • @Jean-BaptisteYunès 不明白多重复杂 IBS 的意思,但是在 awakeFromNib 中处理与 viewDidLoad 具有相同的效果?操作人员正在寻求一种新的方式,而不是通常的方式
  • 我个人不喜欢 propertyObserver 的方式,因为它会延长特定 UIViewController 类中的代码行数,而且可读性也不高!
  • @Sh_Khan 基本上你不能控制出口初始化的顺序,那么在复杂的依赖关系的情况下它是无法用 didSet 管理的
  • 以及为什么我会关心这个,如果最终 var 将被正确设置,并且会得到一个简单的观察者
【解决方案3】:

另请注意,starButtonsCount 不需要是存储变量:

var starButtonsCount: Int {
   return starButtons.count
}

在这种情况下,直接使用starButtons.count 可能会更好,因为该变量根本不会改进代码。

在一般情况下,不需要存储派生状态,除非存储它可以提高性能(例如缓存计算)。

【讨论】:

    【解决方案4】:

    简单的解是一个常数

    let starButtonsCount = 8 // or whatever the number of buttons is
    

    IBOutlets 在构建时连接,因此按钮的数量在运行时不会改变。

    您可以在viewDidLoad 中添加一个断言行,以便在应用程序的未来版本中按钮数量发生变化时得到通知

    assert(starButtons.count == starButtonsCount, "number of buttons has changed, adjust starButtonsCount") 
    

    【讨论】:

    • 抱歉,您的信息似乎不足!实际上,如果我决定添加更多按钮,按钮的数量可能会随着时间而改变。
    • 另外,通过添加assert 行,即使它可以保护应用程序免受失败选项的影响,它是否会使程序更加复杂? (思考)
    • 在这种情况下,您会在 assert 行中遇到致命错误,以更改常量值。
    • 但是感谢您的努力!这也是一些程序的简化。
    • Asserts 仅在 debug 方案中考虑。不需要任何运行时检查或计算永远不会改变的值。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-07-04
    • 1970-01-01
    • 2021-07-08
    • 1970-01-01
    • 2019-12-07
    • 2012-10-11
    • 1970-01-01
    相关资源
    最近更新 更多