I need to be able to keep track of the last user activity (touch on screen). I found this question and answer here however this does not work for me in swift at all. idleTimer.release is not a thing and I just get an error. Also, I am assuming that you have to create an NSTimer since idleTimer is not a thing either unless you make it. I am also confused by the line
idleTimer = [[NSTimer scheduledTimerWithTimeInterval:maxIdleTime target:self selector:#selector(idleTimerExceeded) userInfo:nil repeats:NO] retain];
So, how can I accomplish this in swift? A bit frustrated!
Here's how I do it in my app. Create the timer to check every so often:
self.timer = NSTimer.scheduledTimerWithTimeInterval(
10, target: self, selector: "decrementScore", userInfo: nil, repeats: true)
Now we know that if decrementScore() is called, 10 seconds of idle time went by. If the user does something, we need to restart the timer:
func resetTimer() {
self.timer?.invalidate()
self.timer = NSTimer.scheduledTimerWithTimeInterval(
10, target: self, selector: "decrementScore", userInfo: nil, repeats: true)
}
For each view controller you want to track the last user activity of, create a property with either a NSDate or a NSTimeInterval.
Then, make liberal use of either NSResponder or UIResponder (you didn't specify whether or not you're doing this in iOS or MacOS) methods in your view controller subclass, which is what each application, window and view is built on top of.
UIResponder, for example, has methods for "touchesBegan:withEvent:", and you can reset your view controller's date property each time a touch happens in the view.
Related
I need to figure out how to stop a loop. I've tried a couple different kinds of loops, but the end result is the same - the stop button cannot be pressed while the loop is in progress. Here's what I have so far...
var stopButtonPressed = false
var numArray = [0,1,2,3,4,5,6,7,8,9]
for num in numArray{
print(num)
sleep(2)
if stopButtonPressed {
return
}
}
Obviously the button pressed sets stopButtonPressed to true, but again... the button can't be pressed while the loop is iterating. So what's a better way to do this?
EDIT
#dasblinkinlight
Ok, so I can follow the logic of what you're saying, but the implementation is still confusing. In your example, for the selector, you put "MyClass.doOneStepOfLoop" and that makes perfect sense. Only the timer is unwilling to accept a function as a parameter. So how can I have it do a step if it won't accept a function?
To simplify the problem, how about we just have it print("1") every two seconds? Based off your example, I would think that would look like this...
self.timer = NSTimer.scheduledTimerWithTimeInterval(2, target: self, selector: #selector(print("1")), userInfo: nil, repeats: true)
But this doesn't work and gives the error
Argument of '#selector' does not refer to an initializer or method
I looked through the Q&A you posted as well, and unfortunately I still don't get it. I see lots of pseudo code like "YourClass.doAStep" or "Class.buttonPressed" or "Class.test" in for the selector... could you demonstrate some actual implementation of this?
You misunderstand the way Cocoa applications handle events: the app will not respond to events until your method exits.
The proper way to do something every two seconds is to set up a timer, not to use a loop. Change the handler of stop button press to stop the timer:
// This goes into your viewWillAppear
self.timer = NSTimer.scheduledTimerWithTimeInterval(2, target: self, selector: #selector(MyClass.doOneStepOfYourLoop), userInfo: nil, repeats: true)
// This goes into your stopButtonPressed handler
self.timer.invalidate()
I have set scheduledTimer in a view Controller. But when got to anther view controller, previous view controller timer is continue.Here is my code
var timer: Timer? = Timer.scheduledTimer(timeInterval: 10, target: self, selector: #selector(runTimedCode), userInfo: nil, repeats: false)
Here is function
#objc func runTimedCode() {
//Api Calling
}
when I go to anther viewController, previous Api calling is continue.
Please help me to scheduledTimer go another page/viewcontroller
It's likely that you may not be calling invalidate on the same thread as where you installed the timer. For example, if you installed in on the main thread, wrap invalidate in:
DispatchQueue.main.async(execute: {
self.timer.invalidate()
})
Reference: https://developer.apple.com/documentation/foundation/timer/1415405-invalidate
Timer holds strong reference to current view controller even if your app goes into background or inactive state it still active . Also whenever you push new controller timer is not stoped at all .
Even if you pop your controller it still don't stop timer at this moment . However timer would start with double speed if you initialise timer again . let's understand this problem .
Lets have 3 controllers
HomeScreenVC --> TimerControllerVC --> NewVC
When you initialise timer in TimerController . It create strong reference to your TimerController . Now push NewVC controller on some action method , timer is not stopped at this moment it is still running .
Same case happens with if you pop TimerControllerVC controller to HomeScreenVC . Now you again pushing TimerControllerVC and initialising fresh timer in some method . This time timer would work with 2x speed irrespective of new timer created timer . It creates cycle of recreation if you repeat this step .
Resolving timer issue , remember whenever you declare timer , you must invalidate it in viewwilldissappear method of UIViewcontroller .
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
timer.invalidate()
}
Invalidating timer in some other self declare methods will not helps because there are always some cases when your self declare is not called which will lead to some unexpected issue with timer .
Okey, I have been struggling this for a long time now.. Cant get it to work, and I know there is an easy solution that I cannot find.
I have a UIViewController displaying the main app. When it launches there is two containerViews overlaid that displays a count down for the app to start. Countdown is done, and the "overlay" viewcontrollers are removed from superview.
BUT, I need to call the function to remove VC from superview and start the app in the main UIViewController. But I am not able to trigger this function from the separate "overlay" UIView..
If I make an instance of the UIViewController to trigger the startGame() function it works, but then all the labels return nil, and the app crashes.. I believe this is because the UIViewController is triggered twice?
A lot of explaining here.. I will try to show some outtakes in code:
Main UIViewController:
class DMStartVC: UIViewController {
.....
func startGame() {
self.view.viewWithTag(100)?.removeFromSuperview()
self.view.viewWithTag(101)?.removeFromSuperview()
timer = Timer.scheduledTimer(timeInterval: 1.0, target: self, selector: #selector(DMStartVC.update), userInfo: nil, repeats: true)
UITimer = Timer.scheduledTimer(timeInterval: 0.5, target: self, selector: #selector(DMStartVC.UIUpdate), userInfo: nil, repeats: true)
}
....
}
The UIView handling the "overlay" container views:
class countdown: UIView {
let dmStartVC = DMStartVC()
...
//when animation is done:
dmStartVC.startGame()
}
This causes crash because all labels in the UIViewController is nil.
How can I reach that .startGame() function?
Only way I have been able to solve this is adding a timer inside the DMStartVC to trigger .startGame()... But that is not a good solution as the timer has to trigger at the exact time the countdown ends.. and it never does.
I'm using an NSTimer in an iOS App in background, which is saving some data every 30 seconds in an array. The app shows the last 10 values (values of 5 minutes) in a linechart.
My problem is to use the function of saving data into the array every 30 seconds also in background, when the app isn't on screen. I've written a lot of themes about this, but I don't understand it.
My timer is the following:
timer = NSTimer.scheduledTimerWithTimeInterval(1, target: self, selector: (#selector(ViewController.counting)), userInfo: nil, repeats: true)
func counting() {
timerCounter += 1 //Int
if timerCounter%30==0 {
arrayOfValues.append(...) //Appending the array
reloadLineChart() // reload chart
}
}
Could anyone show me how to solve this? I know, there must be something with the background-methods in the ViewController, but don't now what to type in.
I think there must be a function, which is counting in background and a function that is reloading the chart when I'm back in the app.
I might understand that you don't want to declare the counter in app delegate, for whatever reason you might have,although I would recommend it. However you can call the functions I mentioned, from the same class in which you have defined the counter. You would need to call it like this:
override func viewDidLoad() {
super.viewDidLoad()
NSNotificationCenter.defaultCenter().addObserver(
self,
selector: "applicationWillResignActive:",
name: UIApplicationWillResignActiveNotification,
object: nil)
}
func applicationWillResignActive(notification: NSNotification) {
// stop your counter
}
Then do the same with the other function. Hope is clear.
In your app delegate you can use this method :
func applicationWillResignActive(application: UIApplication) {}
The code you add in this function will run right before your app goes in the background . Therefore you can write there the code to stop the counter.
Afterwards you need to use the following function to activate the counter again:
func applicationWillEnterForeground(application: UIApplication) {}
The code you write in this function will run when you come back to the app again. Hope it is clear enough.
I would like to implement a splash screen for my watch application. After a long check, i haven come to realize there is not a way as for phone and tablet such launchscreen.xib or launch image in info.plist for watch
To implement splash screen, i made a new starting interface, which will only appear when application starts. To do that
for life cycle i have checked this blog
after that in willActivate() func i have implemented
if first {
first = false
var timer = NSTimer.scheduledTimerWithTimeInterval(1, target: self, selector: Selector("update"), userInfo: nil, repeats: false)
}else{
first = true
self.popController()
}
and my update func
func update() {
self.pushControllerWithName("someListsController", context: nil)
}
my point is; i want this interface to show only when application starts, and when returning this interface , application to end.