在第一个视图控制器初始化之前运行代码(基于故事板的应用程序)

时间:2016-01-28 06:29:44

标签: ios uiviewcontroller uistoryboard appdelegate

我的应用程序需要执行一些清理任务 - 在启动时,在显示初始视图控制器之前,删除本地存储的旧数据。

这是因为初始视图控制器在初始化时加载现有数据,并将其显示在表视图中。

我设置了几个断点,发现初始视图控制器的初始值设定项(init?(coder aDecoder: NSCoder))在 application(_:didFinishLaunchingWithOptions)之前运行 - 甚至在{{1}之前,确切地说。

可以将清理代码放在视图控制器的初始化程序的最顶层,但我希望将清理逻辑与任何特定屏幕分离。 该视图控制器最终可能不会成为初始视图控制器。

覆盖app delegate的application(_:**will**FinishLaunchingWithOptions)方法并将我的清理代码放在那里 完成工作,但是......

问题:

是不是有更好/更优雅的方式?

  

注:作为参考,相关方法的执行顺序为   如下:

     
      
  1. AppDelegate.init()
  2.   
  3. ViewController.init()
  4.   
  5. AppDelegate.application(_:willFinishLaunchingWithOptions:)
  6.   
  7. AppDelegate.application(_中:didFinishLaunchingWithOptions:)
  8.   
  9. ViewController.viewDidLoad()
  10.   

澄清:

清理任务不冗长,不需要异步运行:相反,我更喜欢我的初始视图控制器甚至不实例化直到它完成(我 am 意识到如果需要很长时间才能启动,系统会终止我的应用程序。但是,它只是删除了一些本地文件,没什么大不了的。)。

我问这个问题主要是因为,在故事板出现之前,应用启动代码看起来像这样:

init()

...但现在,因为主要故事板加载发生在幕后,视图控制器在任何app委托方法运行之前初始化

正在寻找需要向我的初始视图控制器添加自定义代码的解决方案。

3 个答案:

答案 0 :(得分:4)

我不确定是否有更优雅的方式,但肯定还有其他一些方法......

  

如果我的初步观点,我更喜欢   控制器甚至不会被实例化直到它完成

这不是问题。您所要做的就是从UIMainStoryboardFile中删除NSMainNibFileInfo.plist密钥,该密钥告诉UIApplicationMain应该加载哪个UI。随后你运行你的"清理逻辑"在AppDelegate中,一旦完成,您就会自己启动UI,如示例中所示。

替代解决方案是创建UIApplicationMain的子类,并在加载UI之前在那里运行清理。

请参阅下面的应用生命周期

iOS App Life Cycle

答案 1 :(得分:0)

  1. 您可以在初始ViewController上添加UIImageView,它将包含应用的启动图像。

  2. 在viewDidLoad()中...使imageview.hidden属性为False ...清理操作和清理任务完成后,使imageview.hidden属性为TRUE。

  3. 由此用户将不知道您正在做什么工作,并且这种方法在许多公认的应用程序中使用。

答案 2 :(得分:0)

我遇到了非常相似的情况

我需要运行代码的地方,只有在 didFinishLaunchingNotification 之后才准备好

我想出了这个模式,它也适用于状态恢复

var finishInitToken: Any?

required init?(coder: NSCoder) {
    
    super.init(coder: coder)
    
    finishInitToken = NotificationCenter.default.addObserver(forName: UIApplication.didFinishLaunchingNotification, object: nil, queue: .main) { [weak self] (_) in
        self?.finishInitToken = nil
        self?.finishInit()
    }
    
}

func finishInit() {
    ...
}

override func decodeRestorableState(with coder: NSCoder) {
    
    // This is very important, so the finishInit() that is intended for "clean start"
    // is not called
    if let t = finishInitToken {
        NotificationCenter.default.removeObserver(t)
    }
    finishInitToken = nil
    
}

你也可以为 willFinishLaunchingWithOptions 做一个通知