I am creating a timer inside my ViewController. After it fires once, the program ceases to respond to any further UI events.
I create the timer inside of ViewDidLoad() with:
NSTimer.scheduledTimerWithTimeInterval(1.0, target: self, selector: "initTimerFired", userInfo: nil, repeats: false)
with timer function (defined as method of ViewController):
func initTimerFired(){
println("Timer fired")
}
It successfully fires, but thereafter the program hangs and does not respond to UI events. If I set repeat = true then it runs a couple of times before quitting with EXC_BAD_ACCESS.
I have looked at many different answers and examples, and I can't see what I am doing wrong.
I am running this on an iOS simulator, using xcode 6.1.
Here is an update. Thanks to the suggestions and code provided in the first answer, I have something working. However, my code, which looks to me to be the same, does not work. In order to implement things within the context of a larger project, I want to know how to avoid the errors I am seeing. For instance, this works:
class ViewController: UIViewController {
#IBOutlet weak var strConsole: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
initTaskManager()
}
func initTaskManager(){
let taskManager = NSTimer.scheduledTimerWithTimeInterval(1.0, target: self, selector: "updateTask", userInfo: nil, repeats: true)
}
func updateTask(){
self.strConsole.text = "\(strConsole.text!)Abc"
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
}
But this version does not. Only the function names have changed!:
class ViewController: UIViewController {
#IBOutlet weak var strConsole: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
initTimer()
}
func initTimer(){
let timer1 = NSTimer.scheduledTimerWithTimeInterval(1.0, target: self, selector: "initTimerFired", userInfo: nil, repeats: true)
}
func initTimerFired(){
self.strConsole.text = "\(strConsole.text!)Abc"
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
}
Do not use: initTimerFired, change to something else like: handleTimer,
init as a prefix of the function name may confuse Xcode
See here:
https://developer.apple.com/library/ios/documentation/swift/conceptual/buildingcocoaapps/InteractingWithObjective-CAPIs.html
you have to do like this:
import UIKit
import AVFoundation
class ViewController: UIViewController {
#IBOutlet weak var strConsole: UILabel!
func startTaskManager(){
let taskManager = NSTimer.scheduledTimerWithTimeInterval(1, target: self, selector: "updateTask", userInfo: nil, repeats: true)
}
func updateTask(){
self.strConsole.text = "\(strConsole.text!)Abc"
}
override func viewDidLoad() {
super.viewDidLoad()
startTaskManager()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
}
Related
import UIKit
class ViewController: UIViewController {
#IBOutlet weak var imageView: UIImageView!
var timer = Timer.scheduledTimer(timeInterval: 2, target: self, selector: #selector(ViewController.runTimedCode), userInfo: nil, repeats: true)
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
#objc func runTimedCode() {
imageView.image = UIImage(named: "card10")
}
}
This code gives me the message "unrecognized selector sent to instance" but i do not know what the problem is. Can someone please help me? :)
Try this instead:
class ViewController: UIViewController {
#IBOutlet weak var imageView: UIImageView!
var timer: Timer? = nil
override func viewDidLoad() {
super.viewDidLoad()
timer = Timer.scheduledTimer(timeInterval: 2, target: self, selector: #selector(ViewController.runTimedCode), userInfo: nil, repeats: true)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
#objc func runTimedCode() {
imageView.image = UIImage(named: "card10")
}
}
you have to call the function like bellow.
var timer:Timer?
override func viewDidLoad(){
super.viewDidLoad()
timer = Timer.scheduledTimer(timeInterval: 1.0, target: self, selector: #selector(self.runTimedCode), userInfo: nil, repeats: true)
}
#objc func runTimedCode(){
print("timer is calling")
}
Is there an easy way to deselect an NSTextField after pressing enter?
First you will need to make your view controller the delegate of your text field. Then you override NSControl instance method controlTextDidEndEditing(_:), get your textfield current editor selected range
and from the main thread set it back to your textfield:
import Cocoa
class ViewController: NSViewController, NSTextFieldDelegate {
#IBOutlet weak var textField: NSTextField!
override func viewDidLoad() {
super.viewDidLoad()
textField.delegate = self
}
override func controlTextDidEndEditing(_ obj: Notification) {
if let selectedRange = textField.currentEditor()?.selectedRange {
DispatchQueue.main.async {
self.textField.currentEditor()?.selectedRange = selectedRange
}
}
}
}
Here is one way I did it.
By disabling it with isSelectable and isEditable and then setting a timer to re-enable it after 0.5s
#IBAction func timeCodeChanged(_: NSTextField) {
timecodeLabel.isSelectable = false
timecodeLabel.isEditable = false
Timer.scheduledTimer(timeInterval: 0.5, target: self, selector: #selector(reEnableLabel), userInfo: nil, repeats: false)
}
#objc func reEnableLabel() {
timecodeLabel.isSelectable = true
timecodeLabel.isEditable = true
}
I'm working on autocompletion in my project and I would like to detect when the textfieldDidChange value and call a method (link to API) 500MS after that.
I hope it's clear enough
Thank for your help !
In Swift 3, you probably want to connect to "editing changed" not "value changed", and reset the timer and start another timer:
weak var timer: Timer?
#IBAction func didChangeEditing(_ sender: UITextField) {
timer?.invalidate()
timer = .scheduledTimer(withTimeInterval: 0.5, repeats: false) { [weak self] timer in
// trigger your autocomplete
}
}
Or you can alternatively hook into shouldChangeCharactersIn. For example:
class ViewController: UIViewController, UITextFieldDelegate {
#IBOutlet weak var textField: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
textField.delegate = self // or you can do this in IB
}
weak var timer: Timer?
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
timer?.invalidate() // cancel prior timer, if any
timer = .scheduledTimer(withTimeInterval: 0.5, repeats: false) { [weak self] timer in
// trigger your autocomplete
}
return true
}
}
First make sure to make your class the TextField's delegate:
class yourClass: UIViewController, UITextFieldDelegate{
//...
}
And then in viewDidLoad():
textField.delegate = self
numbersTextField.addTarget(self, action: #selector(self.textFieldDidChange), for: .editingChanged)
After that, you can use a timer, like this:
var timer = Timer()
var count = 0
func textFieldDidChange(textField: UITextField){
timer.invalidate()
timer = Timer.scheduledTimer(timeInterval: 0.1, target: self, selector: #selector(self.timerFunc), userInfo: nil, repeats: true)
}
func timerFunc(){
count += 1
if count == 5{
timer.invalidate()
// do your things here down here, I assumed that your method is called autocomplete
autocomplete()
}
}
Hope it helps!
I'm kind of at a wall of what to do, the program runs, but the timer.invalidate() does not work? Any tips are welcome.
I worked with this program in the past and worked through it and the timer.invalidate() worked flawlessly. I do not believe that it has to do with the fact that I put it into a function because before it wasn't working when I was just typing "timer.invalidate()" instead of "stop()"
Whenever I click the button Cancel on the iOS simulator it just resets it back to 0, but keeps counting.
Thanks in advance.
import UIKit
class ViewController: UIViewController {
var timer = NSTimer()
var count = 0
#IBOutlet weak var timeDisplay: UILabel!
#IBAction func playButton(sender: AnyObject) {
//play button
var timer = NSTimer.scheduledTimerWithTimeInterval(1, target: self, selector: Selector("result"), userInfo: nil, repeats: true)
}
#IBAction func resetTimer(sender: AnyObject) {
//cancel button
stop()
count = 0
timeDisplay.text = "0"
}
#IBAction func pauseButton(sender: AnyObject) {
stop()
}
func result() {
count++
timeDisplay.text = String(count)
}
func stop () {
timer.invalidate()
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
In playButton() you are defining another timer, that can't be invalidated from outside this function - so by calling timer.invalidate() you invalidate just var timer = NSTimer() which doesn't carry any set timer in it.
So replace
var timer = NSTimer.scheduledTimerWithTimeInterval(1, target: self, selector: Selector("result"), userInfo: nil, repeats: true)
with
timer = NSTimer.scheduledTimerWithTimeInterval(1, target: self, selector: Selector("result"), userInfo: nil, repeats: true)
It worked in swift beta4 and now i have GM version
but this error says hello
how can i solve this problem?
"Could not find an overload for 'init' that accepts the supplied arguments" in 2 parts
var timer = NSTimer()
var counter : Double = 7.0
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
labelCounter.text = String(counter) <- error here
}
#IBOutlet weak var labelCounter: UILabel!
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
#IBAction func startCounterPressed(sender: AnyObject) {
timer.invalidate()
timer = NSTimer.scheduledTimerWithTimeInterval(0.1, target: self, selector: Selector("update"), userInfo: nil, repeats: true)
}
func update() {
sth cool
}
#IBAction func pauseCounterPressed(sender: AnyObject) {
timer.invalidate()
}
#IBAction func stopCounterPressed(sender: AnyObject) {
timer.invalidate()
counter = 7.0
labelCounter.text = String(counter) <- error here
String class overload init method for double.
let s = NSString(format: "%.2f", counter)