Reputation: 13
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
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
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
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
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