0

i want to restart app from first view like that:

func applicationWillEnterForeground(_ application: UIApplication) {
    let storyBoard: UIStoryboard = UIStoryboard(name: "SplashScreen", bundle: nil)
    let splashScreen = storyBoard.instantiateViewController(withIdentifier: "splashVC") as! SplashScreenController
    self.window?.addSubview(splashScreen.view)

}

But when app is waked up again. My delegate return nil. Why?

SplashScreenVM.swift:

  import Foundation
protocol SplashScreenVMProtocol: class {
    func fetchDataSuccessfuly()
    func failedFetchData()
}
class SplashScreenVM {

    weak var delegate: SplashScreenVMProtocol!
    private let dataManager = DataManagement()
    private let coreDataManager = CoreDataManagement()

    lazy var itemsCount = coreDataManager.getRecords("Categories").count
    lazy var timestamp = coreDataManager.getRecords("Timestamp")

    init(){}

    func setUpData() {
        dataManager.fetchData(timestamp: 0 ) { (err, res) in
        //dataManager.fetchData(timestamp: timestamp.count == 0 ? 0 : timestamp[0].value(forKey: "time") as! Int64) { (err, res) in
            //print("categories count: \(self.coreDataManager.getRecords("Categories").count) and artciles count \(self.coreDataManager.getRecords("Articles").count)")

            if(err != nil) {
                print("Error: \(String(describing: err))");
                self.delegate.failedFetchData()
                return
            }
                self.coreDataManager.setTimestamp()
                self.delegate.fetchDataSuccessfuly()
        }
    }
}

My first view when app is opened SplashScreenController:

    import UIKit
import Alamofire

class SplashScreenController: UIViewController, SplashScreenVMProtocol {

    @IBOutlet weak var loadSpinner: UIActivityIndicatorView!

    let splashScreenVM = SplashScreenVM()

    let storyBoard: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
    lazy var MainController = storyBoard.instantiateViewController(withIdentifier: "MainVC")

    override func viewDidLoad() {
        super.viewDidLoad()


        splashScreenVM.delegate = self  //Looks like something wrong with this
        print("apapapaap \(splashScreenVM.delegate)")
        loadSpinner.hidesWhenStopped = true
        loadSpinner.startAnimating()

        switch Reachability.isConnectedToNetwork() {
            case true:
                splashScreenVM.setUpData()
            case false:
                self.loadSpinner.stopAnimating()
                splashScreenVM.itemsCount == 0 ? print("butinai reikia intiko") : print("keliaujam i pagr.meniu")
        }
    }

    func fetchDataSuccessfuly() {
        self.loadSpinner.stopAnimating()
        self.present(MainController, animated: true, completion: nil)
    }

    func failedFetchData() {
        self.loadSpinner.stopAnimating()
        if(splashScreenVM.itemsCount != 0) {
            self.present(MainController, animated: true, completion: nil)
        }
        return
    }   
}

What i'm doing wrong? My weak var delegate: SplashScreenVMProtocol! returns nil. Is it better way to start app from begining when app is awake again?

Marius
  • 25
  • 1
  • 13
  • forgot to mention that error appears in self.delegate.fetchDataSuccessfuly() line, "found nil when unwrapping value.." – Marius Sep 13 '18 at 14:12
  • 1
    your delegate should be an optional, replace ! with ? – Do2 Sep 13 '18 at 14:20
  • and how that will solve the problem? – Marius Sep 13 '18 at 14:30
  • @Marius Have a look at this to explain the reasoning behind ! and ?. [what does an exclamation mark mean in the swift language](https://stackoverflow.com/questions/24018327/what-does-an-exclamation-mark-mean-in-the-swift-language) – MwcsMac Sep 13 '18 at 16:04
  • MwcsMac really? it doesn't make diference for me... I still will get delegate nil whatever is ! or ?. When i put ? at the end it will just prevent app from crash. Look at the question first of all -> "My delegate return nil. Why?"... – Marius Sep 13 '18 at 16:18

2 Answers2

0

You're not retaining your splashScreen variable in the applicationWillEnterForeground. You set the splashScreen view as a subview, but splashScreen itself is just a local variable. When it goes out of scope the object will be released.

Your data access is happening async, so when it completes, the original splashScreen object has already been released and no longer exists.

Something needs to hold onto splashScreen.

A. Johns
  • 199
  • 4
0

Well i solved the problem, maybe... just changed from weak var delegate: SplashScreenVMProtocol! to var delegate: SplashScreenVMProtocol! and works great but in console i get this "Presenting view controllers on detached view controllers is discouraged"

Marius
  • 25
  • 1
  • 13