antonyraja antonyraja - 23 days ago 7
Swift Question

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

Answer

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:

http://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.

Comments