Swift Runtime exception: unrecognized selector - swift

In my ViewController class, I have a function:
func updateTimes() {
// (code)
}
I create a timer:
class ViewController: NSViewController {
var timer = Timer.scheduledTimer(timeInterval: 5,
target: self,
selector:
#selector(ViewController.updateTimes),
userInfo: nil,
repeats: true)
The compiler is happy with this. At runtime, when the timer fires, I get an exception:
unrecognized selector sent to instance 0x6000000428b0
Am I doing something obviously wrong?

As I wrote as a comment on NaGib ToroNgo's answer, he has given us a nice suggestion.
The selector may not be sent to the instance of ViewController.
I guess the ViewController would be taking this form:
class ViewController: UIViewController {
var timer = Timer.scheduledTimer(timeInterval: 5,
target: self,
selector: #selector(ViewController.updateTimes),
userInfo: nil,
repeats: true)
//...(Other property declarations or method definitions)...
func updateTimes() {
// (code)
}
}
The variable timer is declared as an instance property, and self is used in an initial value of timer. (In some old versions of Swift, this sort of usage caused error, so I was thinking that this line exists in any of the methods.)
In the current version of Swift (tested with Swift 3.1/Xcode 8.3.3), the code above does not cause error, but self is interpreted as a method reference of self() method declared in NSObjectProtocol. So, Selector("updateTimes") is sent to the closure representing the method reference (curried function), not to the instance of the ViewController.
The closure does not have a method named updateTimes, which caused the exception:
unrecognized selector sent to instance
Move the initial value code into some instance context, and then self represents the instance of the ViewController:
class ViewController: UIViewController {
var timer: Timer? //<- Keep `timer` as an instance property, but move the initial value code into `viewDidLoad()`.
//...(Other property declarations or method definitions)...
override func viewDidLoad() {
super.viewDidLoad()
//Do initialize the timer in the instance context.
timer = Timer.scheduledTimer(timeInterval: 5,
target: self,
selector: #selector(self.updateTimes),
userInfo: nil,
repeats: true)
//...
}
//In Swift 3, `#objc` is not needed, just for a preparation for Swift 4
#objc func updateTimes() {
// (code)
}
}
I believe this does not cause unrecognized selector exception.

The code you have provided seems perfect. I think the problem is, somehow your view controller is getting released or having dangling pointer.

Its time to say good bye to selectors!!! use the below code
Timer.scheduledTimer(withTimeInterval: 5, repeats: true) { (timer) in
// check self for nil before using
}

Related

App just crashes when changing station? - AppDelegate error

So I am getting the following error code
Thread 1: Exception: "-[__NSCFTimer copyWithZone:]: unrecognized selector sent to instance 0x281e8a1c0"
However I have no idea what sent to what instance the error is highlighted on this line
class AppDelegate: UIResponder, UIApplicationDelegate {
The only command I ran is the following
#objc func playdrn1(sender:UIButton!){
MusicPlayer.shared.startBackgroundMusic(url: "http://stream.radiomedia.com.au:8006/stream?uuid=\(uuid ?? "")")
nowplaying(npurl:"https://api.drn1.com.au/station/DRN1/playing")
}
I have narrowed the error to the nowplaying function.
it seems not to like the fact am looping or something like that
func scheduledTimerWithTimeInterval(){
// Scheduling timer to Call the function "updateCounting" with the interval of 1 seconds
timer = Timer.scheduledTimer(timeInterval: 30, target: self, selector: #selector(self.nowplaying), userInfo: nil, repeats: true)
}
The issue is am not sending npurl info with the self.nowplaying.
#selector(self.nowplaying)
How can I make #objc func nowplaying(npurl:String){ run without resending the npurl?
The signature #objc func nowplaying(npurl:String) { is wrong. You cannot pass a custom parameter type
A timer action method can have two forms
#objc func nowplaying() { ...
and
#objc func nowplaying(_ timer : Timer) { ...
Either pass the string in the userInfo dictionary or create a temporary property.

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.

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").