antonyraja
antonyraja

Reputation: 13

How to call timer one time in application using swift?

Hi all am developing a app using swift 2 in my app am updating current location for every x minutes so am using NSTimer am able to update location and everything works fine.In my app(first view controller) when a user successfully logged in and moves to second view controller in(second view controller) i wrote the function for updating location using NSTimer it works fine but when the user moves to third view controller and return to second view controller it again start updating location so i cant able to stop the timer twice it invalidate timer one time only other one keep on updating the location even after the users logged out.so please someone help me out to solve this problem.

my second view controller:

class secondviewcontroller:UIViewController{

in view did load method:

  var appDelegate:AppDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
             appDelegate.timer = NSTimer.scheduledTimerWithTimeInterval(10.0, target: self, selector: #selector(timeToMoveOn), userInfo: nil, repeats: true)

 //i declared var timer:nstimer! in appdelegate.swift and i performed some function using nstimer

my third view controller:

I created a button action for logout code is:

  var appDelegate:AppDelegate = (UIApplication.sharedApplication().delegate as?
            AppDelegate)!
         appDelegate.timer.invalidate()

Thanks in advance

Hi all thank you for your support i found the answer for my question

i just kept timer.invalidate() in two different methods according to my project

Upvotes: 2

Views: 2203

Answers (4)

J.Doe
J.Doe

Reputation: 96

timer's target is second viewController, second viewController owns this object, AppDelegate only reference to this object, AppDelegate can't release this object and only secondViewController can. Unless secondViewController is destruction

so:

var timer:NSTimer//global variable

in secondViewController's viewDidLoad method:

timer = NSTimer.scheduledTimerWithTimeInterval(10.0, target: self, selector: #selector(timeToMoveOn), userInfo: nil, repeats: true)

in thirdViewController:

let timer =  (secondViewControllers object)'s timer
timer.invalidate()

Upvotes: 2

Vyacheslav
Vyacheslav

Reputation: 27211

I would suggest to do this:

this singleton to wrap location.

Sorry, for swift3 but it have look something like this:

class LM: NSObject, CLLocationManagerDelegate {
    //MARK: Public Variable

    var lat = 0.0
    var lon = 0.0
    var CAST = "location_cast"
    public static let i : LM = {
        let instance = LM()
        return instance
    }()

    //MARK: Local Variable

    fileprivate var locationManager: CLLocationManager?

    //MARK: Init
    public override init() {
        super.init()
        locationManager = CLLocationManager()
        locationManager?.delegate = self
    }
    internal func start() {
        locationManager?.startUpdatingLocation()
    }
    internal func stop() {
        locationManager?.startUpdatingLocation()
    }
    func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) {
        //code
        print("\(error)")
    }
    func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
        //code
//        print("\(locations)")
        if let loc = locations.last {
//simple store to retrieve it later
            lat = loc.coordinate.latitude
            lon = loc.coordinate.longitude


                //cast here notification
                NotificationCenter.default.post(name: NSNotification.Name(rawValue: CAST), object: ["lat": lat, "lon": lon])
        }

    }
    func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {
        switch status {
        case .notDetermined:
            manager.requestAlwaysAuthorization()
            break
        case .authorizedWhenInUse:
            manager.startUpdatingLocation()
            break
        case .authorizedAlways:
            manager.startUpdatingLocation()
            break
        case .restricted:
            // restricted by e.g. parental controls. User can't enable Location Services
            break
        case .denied:
            // user denied your app access to Location Services, but can grant access from Settings.app
            break
        }
    }
}

to start and stop this locationmanager use this:

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
//...
var window: UIWindow?

    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey : Any]? = nil) -> Bool {
// Override point for customization after application launch.
        _  = LM.i
        return true
    }

func applicationWillResignActive(_ application: UIApplication) {
        // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.

       LM.i.stop()
    }

 func applicationDidBecomeActive(_ application: UIApplication) {
        // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.

        LM.i.start()
    }
}

You can add inside AppDelegate your custom timer with casting variables each 1 second

let CASTTOVIEWCONTROLLER = "CASTTOVIEWCONTROLLER"
 NotificationCenter.default.post(name: NSNotification.Name(rawValue: CASTTOVIEWCONTROLLER), object: ["lat": LM.i.lat, "lon": LM.i.lon])

or even simple

 let CASTTOVIEWCONTROLLER_PING = "CASTTOVIEWCONTROLLER_PING"
NotificationCenter.default.post(name: NSNotification.Name(rawValue: CASTTOVIEWCONTROLLER), object: nil)

to catch a new data from casted values use something like this:

https://stackoverflow.com/a/38615219/1979882

If you will not manage .start() and .stop() iOS will kick your background timer application each in several minutes if your will press 'home' button.

Upvotes: 2

Gourav Joshi
Gourav Joshi

Reputation: 2419

As I see your code, Please add a flag or Bool variable in your AppDelegate Class. Now when you comes on second screen from First screen the flag will be enable and when you want to navigate to third screen set false to flag and by checking flag is true or not your timer will be run by true condition. Now when you again come in second screen from 3rd and if timer case again arise then plz refer this link: NSTimer Not Stopping When Invalidated

Hopes it will helps you

Upvotes: 1

User511
User511

Reputation: 1486

Instead of pushing from third view controller to second view controller. You can pop to second view controller. Then your viewDidLoad will not call.

Upvotes: 2

Related Questions