0

I already know how to save things and I can automatically load them when opening the app. But I have no idea how to save them as it closes! I have a button for now. I am trying to save just one value, StreakNumber. However, whenever I try, I fail.

When in app delegate I try saying ViewController.AppSave(ViewController). I get an error:

Editor placeholder in source file Expression resolves to an unused function

and if I use ViewController.AppSave() I get the following error:

Instance member 'SaveApp' cannot be used on type 'ViewController'; did you mean to use a value of this type instead?

import UIKit
import UserNotifications

class ViewController: UIViewController {
    //TEST PLAY AREA//

    @IBAction func SaveButton(_ sender: Any) {
        SaveApp()
    }

    @IBAction func LoadButton(_ sender: Any) {
        LoadApp()
    }

    ///TEST PLAY AREA ENDS
    public var streakNumber = 0
    public var  streakNumberString = ""

    public var activated = false

    let defaults = UserDefaults.standard
    //Labels
    @IBOutlet var streakNumberLabel: UILabel!

    @IBOutlet var remainingTimeTextLabel: UILabel!

    @IBOutlet var remainingTimeNumberLabel: UILabel!
    //Buttons
    @IBAction func startButton(_ sender: Any) {
        Activate()

    }
    @IBAction func stopButton(_ sender: Any) {
        Deactivate()
        seconds = 59
        minutes = 59
        hours = 47

    }

    //Timer
    var timer = Timer()
    var seconds = 0
    var minutes = 0
    var hours = 0

    // Nitifications
    //END
    override func viewDidLoad() {
        super.viewDidLoad()

        LoadApp()

        // this enables notifications
        UNUserNotificationCenter.current().requestAuthorization(options:[.alert , .sound , .badge], completionHandler:{ didAllow, error in
        })
    }

    func Activate (){
        if activated == false {
            streakNumber += 1

        }
        activated = true
        streakNumberLabel.text = String(streakNumber)
    }

    func Deactivate (){
        if activated == true{
            activated = false
            ActivTimer()

            // Notification
            let content = UNMutableNotificationContent()
            content.title = " 10  secodns are up "
            content.subtitle = " yep time passed"
            content.body = " The 10 seconds are really up!!"
            content.badge = 1
            let trigger = UNTimeIntervalNotificationTrigger(timeInterval: 600, repeats:false)
            let request = UNNotificationRequest(identifier: "timerDone", content: content , trigger: trigger)
            UNUserNotificationCenter.current().add(request,withCompletionHandler:nil)
        }
    }

    @objc func Clock(){
        seconds = seconds-1
        if seconds == -1{
            seconds = 59
            minutes = minutes-1
        }
        if minutes  == -1{
            minutes  = 59
            hours = hours-1
        }
        remainingTimeNumberLabel.text = (String(hours) + ":" + String(minutes) + ":" + String(seconds))
        if seconds == 0 && hours == 0 && minutes == 0 {

            timer.invalidate()

        }
    }

    func ActivTimer(){
        timer = Timer.scheduledTimer(timeInterval: 1, target: self, selector: #selector(ViewController.Clock), userInfo: nil, repeats: true)
    }//SAVING STUFF DOESNT WORK
    //

    func SaveApp(){
        streakNumberString = String(streakNumber)
        defaults.set(streakNumberString, forKey: "streakNumbers")
        print("Saved" + String(defaults.integer(forKey: "streakNumbers")))

    }

    func LoadApp(){
        streakNumberString =  defaults.string(forKey: "streakNumbers")!
        print (defaults.integer(forKey: "streakNumbers") )
        streakNumber = Int(streakNumberString)!
        streakNumberLabel.text = String(streakNumber)
    }//
}
rmaddy
  • 314,917
  • 42
  • 532
  • 579
  • appdidEnterBackground & willEnterforeground is the best place. Have a look 1. https://stackoverflow.com/questions/9011868/whats-the-best-way-to-detect-when-the-app-is-entering-the-background-for-my-vie 2. https://stackoverflow.com/questions/9599431/is-there-any-notification-to-get-before-application-did-enter-background 3. https://stackoverflow.com/questions/9039606/refresh-data-after-entering-a-foreground 4. https://stackoverflow.com/questions/10648388/ios-app-applicationwillenterforeground-and-it-stucked-for-a-while – Gagan_iOS Oct 23 '17 at 16:47
  • Most of the code you posted has nothing to do with the code causing your errors. Please [edit] your question to include relevant code. Include the actual code you have tried that is causing your issues. – rmaddy Oct 23 '17 at 16:54

1 Answers1

0

The error says it all. You can't invoke SaveApp() on ViewController. You actually need an instance of the ViewController to invoke SaveApp() on itself.

If you wish your ViewController instance to save its data on App termination, you could post a Notification from the AppDelegate's applicationDidEnterBackground method, which is called whenever the app is being minimized and before termination as well:

func applicationDidEnterBackground(_ application: UIApplication) {

    NotificationCenter.default.post(Notification(name: Notification.Name("AppAboutToTerminateOrMinimize")))
}

Then you could subscribe to that notification in your ViewController's viewDidLoad():

NotificationCenter.default.addObserver(self,
                                       selector: #selector(AppSave),
                                       name: Notification.Name("AppAboutToTerminateOrMinimize"),
                                       object: nil)

Or as rmaddy mentioned in the comments, you can just put the below code in ViewController's viewDidLoad() and skip the AppDelegate part:

NotificationCenter.default.addObserver(self,
                                       selector: #selector(AppSave),
                                       name: Notification(name: UIApplicationDidEnterBackgroundNotification,
                                       object: nil)

This way when the app minimizes/terminates the AppDelegate will send notification, the ViewController instance (if alive) will receive it and will call AppSave()

You'd have to annotate AppSave() method as @objc

And it's a good practice to use lowerCamelCase for naming of properties and methods /i.e appSave() instead of AppSave()

Dan
  • 619
  • 1
  • 8
  • 18
  • There is a much better way to do this. Simply have the view controller register for the `UIApplicationDidEnterBackground` notification. No need for a custom notification. No need to post anything in the `applicationDidEnterBackground` app delegate method. – rmaddy Oct 23 '17 at 17:05
  • @rmaddy how do i do so? – Damian Talaga Oct 23 '17 at 17:36
  • @Dan i ham still having issues as i copied your code, changed app save to SaveApp, i still get a notification in the second line Type of expression is ambiguous without more context – Damian Talaga Oct 23 '17 at 17:54
  • Could you post your edited `SaveApp()` and `viewDidLoad()` methods? – Dan Oct 24 '17 at 06:50