Pass a reference/pointer to a method called with NSTimer? - swift

I have a timer calling a method that needs to have two references to other variables (gravity and player)
func update(inout gravity: CGVector, inout player: Player) {
timer = NSTimer.scheduledTimerWithTimeInterval(0.1, target: self, selector: Selector("myMethod"), userInfo: gravity, repeats: true) // Here I get the error: extra argument 'selector' in call
}
func myMethod() {
println(timer.userInfo.gravity.dx)
}
While the above works for contants or regular variables, when I try to pass a pointer or an inout variable I get the error "Extra argument 'selector' in call". How can I pass the references to the variables to myMethod?

Try it without the Selector:
timer = NSTimer.scheduledTimerWithTimeInterval(0.1, target: self, selector: "myMethod", userInfo: gravity, repeats: true)
This is the format that works for me. Also, in my tests, if you pass gravity as userInfo, and gravity as a memory property, you can access it like this:
func myMethod() {
println(timer.userInfo.memory)
}

Related

Repeat function using NSTimer fails with target: self in Swift

I found this question and tried to copy the code to my Xcode project, but I'm getting the following error message.
error: use of unresolved identifier 'self'
What's the right way?
EDIT: Here the code, tested in a playground:
//: Playground - noun: a place where people can play
import Cocoa
import Foundation
func sayHello() {
print("hello World")
}
var SwiftTimer = NSTimer()
SwiftTimer = NSTimer.scheduledTimerWithTimeInterval(1, target:self, selector: Selector("sayHello"), userInfo: nil, repeats: true)
Usually using uppercase to the properties name it's considered as a bad attitude, you should use swiftTimer.
These expressions are not allowed ad the top level:
var swiftTimer = NSTimer()
swiftTimer = NSTimer.scheduledTimerWithTimeInterval(1, target:self, selector: Selector("sayHello"), userInfo: nil, repeats: true)
You must put it in a function like for example:
override func viewDidLoad() {
super.viewDidLoad()
var swiftTimer = NSTimer()
swiftTimer = NSTimer.scheduledTimerWithTimeInterval(1, target:self, selector: Selector("sayHello"), userInfo: nil, repeats: true)
}
self refers to the object for which a method (a function defined within a class) is defined, so can only be used in a method. (It is the equivalent of this in C++/Java/Javascript.) In your code, sayHello() is a global function, not a method, so there is no self to refer to.
In order for the scheduledTimerWithTimeInterval() function call to work with those arguments, it must be called within an instance method so that there is a self, and that class must have a method named sayHello().
You could also change the target: to another object as long as that object has a sayHello() method.
Basically an asynchronous timer doesn't work in a Playground and a since the top level of a Playground isn't a class there is no self property.
To test NSTimer in a Playground
Wrap the timer in a class.
Import XCPlaygound.
Add XCPlaygroundPage.currentPage.needsIndefiniteExecution = true to enable support of asynchronous tasks.

Swift Selector is never called for NSTimer

I have the following instance method in my Swift class Sentence which makes a call to a NSTimer which calls the class instance method as its Selector. When I run the program without breakpoints, it gets to the first NSTimer successfully but then stalls at NSTimer. When I add a breakpoint to see if sentenceDidFinish is ever called, I see that it never is, proving it stops at the first NSTimer.
class Sentence : NSObject {
//init() etc.
func playEvent(eventIndex : Int){
if (eventIndex < 2){
let currEvent = self.eventArray[eventIndex]
currEvent.startEvent()
let nextIndex = eventIndex + 1
print("Play Event event id is ", eventIndex)
NSTimer.scheduledTimerWithTimeInterval(currEvent.duration, target: self, selector: Selector("playEvent:"), userInfo: NSNumber(integer: nextIndex), repeats: false)
}
else if (eventIndex==2){
self.eventArray[eventIndex].startEvent()
print("Play Event event id is ", eventIndex)
NSTimer.scheduledTimerWithTimeInterval(0.4, target: self, selector: Selector("sentenceDidFinish"), userInfo: nil, repeats: false)
}
else{
//DO Nothing
}
}
func sentenceDidFinish(){
//foo
//bar
}
}
Here is the full .swift file:
https://gist.github.com/anonymous/e0839eae1d77e1e4b671
When you call playEvent: with the timer, the argument passed will be the timer itself, not the integer. But in the declaration for eventIndex you are acting as if it will be the integer.
Try adding a method like this:
func handleTimer(timer: NSTimer) {
playEvent(timer.userInfo as! Int)
}
Then call the first timer like this:
NSTimer.scheduledTimerWithTimeInterval(0.4, target: self, selector: "handleTimer:", userInfo: NSNumber(integer: nextIndex), repeats: false)
The forced casting (as!) will crash if userInfo isn't castable to Int. Safer, but more verbose would look like:
func handleTimer(timer: NSTimer) {
guard let index = timer.userInfo as? Int else { return }
playEvent(index)
}

Cannot create Struct with CGRect based on super.view.frame [duplicate]

Just a simple task, but I'm in trouble. Trying to make a different way but it fails.
How to init NSTimer with declared previously variable? Neither var nor let helps.
The initial value of a property (in your case: timer) cannot depend on another property of the class (in your case: interval).
Therefore you have to move the assigment timer = NSTimer(interval, ...) into a method of the
class, e.g. into viewDidLoad. As a consequence, timer has to be defined as an
optional or implicitly unwrapped optional.
Note also that Selector(...) takes a literal string as argument, not the method itself.
So this should work:
class ViewController: UIViewController {
var interval : NSTimeInterval = 1.0
var timer : NSTimer!
func timerRedraw() {
}
override func viewDidLoad() {
super.viewDidLoad()
timer = NSTimer(timeInterval: interval, target: self, selector: Selector("timerRedraw"), userInfo: nil, repeats: true)
// ...
}
// Other methods ...
}
Try:
var interval:NSTimeInterval = 1.0
var timer = NSTimer.scheduledTimerWithTimeInterval(interval, target: self, selector: "timerRedraw:", userInfo: nil, repeats: true)
pro-tip and hopefully an appreciated FYI: Swift functions should also start with lower case letters (i.e. "timerRedraw").

NSTimer Swift difficulty

I am trying to create a NSTimer so that I can move a UIImageView down but
The NSTImer is having difficulty, saying first that this.
var timer = NSTimer.scheduledTimerWithTimeInterval(0.5, target:self(), selector: Selector ("mrockdown"), userInfo: nil, repeats: true)
is missing argument for parameter #1 in call. But when I remove the brackets from the target:self() it tells me
Cannot invoke 'scheduledTimerWIthTimerInterval' with an argument list of type '(Double, target: ViewController -> () -> ViewController, selector: Selector, userinfo: nil, repeates Bool.
What should I do?
The problem has to do with where you are saying this. It looks like you are trying to say this as part of a property declaration:
class ViewController {
var timer = ...
// ...
}
But you can't do that, because there is no self as far as a stored property is concerned. You need to declare the timer as an Optional and then initialize it later:
class ViewController {
var timer = NSTimer!
func someMethod {
timer = ...
}
}
Then you will remove the parentheses (they are wrong) and everything will compile just fine.
You can do this inside the function where you want to trigger the timer (i.e. viewDidLoad or some IBAction)
_ = Timer.scheduledTimer(timeInterval: yourInterval, target: self, selector: #selector(yourFunction), userInfo: nil, repeats: true)
That being said, to animate a view you should use this instead:
UIView.animate(withDuration: yourDuration) {
// set yourView's final position here
}

Swift dictionary with String key and UIImageView as value [duplicate]

Just a simple task, but I'm in trouble. Trying to make a different way but it fails.
How to init NSTimer with declared previously variable? Neither var nor let helps.
The initial value of a property (in your case: timer) cannot depend on another property of the class (in your case: interval).
Therefore you have to move the assigment timer = NSTimer(interval, ...) into a method of the
class, e.g. into viewDidLoad. As a consequence, timer has to be defined as an
optional or implicitly unwrapped optional.
Note also that Selector(...) takes a literal string as argument, not the method itself.
So this should work:
class ViewController: UIViewController {
var interval : NSTimeInterval = 1.0
var timer : NSTimer!
func timerRedraw() {
}
override func viewDidLoad() {
super.viewDidLoad()
timer = NSTimer(timeInterval: interval, target: self, selector: Selector("timerRedraw"), userInfo: nil, repeats: true)
// ...
}
// Other methods ...
}
Try:
var interval:NSTimeInterval = 1.0
var timer = NSTimer.scheduledTimerWithTimeInterval(interval, target: self, selector: "timerRedraw:", userInfo: nil, repeats: true)
pro-tip and hopefully an appreciated FYI: Swift functions should also start with lower case letters (i.e. "timerRedraw").