I am switching over the syntax of my project toward Swift 2.2 (which xCode helps me do automatically); however, I do not understand the new #selector() syntax.
As an example:
timer = NSTimer.scheduledTimerWithTimeInterval(1.0, target: self,
selector: #selector(MyVC.timerCalled(_:)), //new selector syntax!
userInfo: nil, repeats: true)
This has the selector #selector(MyVC.timerCalled(_:))
What does the _: signify? Can you add other variables into this selector? Say, #MyVC.timerCalled(_:whateverVar).
General info on what is different in this syntax as opposed to the string based implementation from earlier versions of Swift are greatly appreciated.
The bit in parenthesis is a mechanism for identifying the argument list for the selector that you want.
I recommend you look at the Generalized Naming proposal from Swift Evolution. It covers cases where you have a number of functions that differ only by their parameter labels and need to refer to them. The example from that document is:
extension UIView {
func insertSubview(view: UIView, at index: Int)
func insertSubview(view: UIView, aboveSubview siblingSubview: UIView)
func insertSubview(view: UIView, belowSubview siblingSubview: UIView)
}
If you wanted to get a function value for one of those the result is ambiguous:
let fn = someView.insertSubview // ambiguous: could be any of the three methods
The solution implemented is to add the argument labels, without any type information to the code that generates the function value to disambiguate which you want:
let fn = someView.insertSubview(_:at:)
let fn1 = someView.insertSubview(_:aboveSubview:)
See how the labels are added in the parens?
This proposal played a role in the one that most directly applies to your question:
Referencing the Objective-C selector of a method
In this particular case the selector you want to refer to is timerCalled: which is a function of one parameter that has no label. Hence (_:). The underscore means the label is not specified and the colon.
Swift 2.2 has deprecated Stringified selectors: In swift 2.0, we use to write the selector as a String i.e "buttonClicked". The disadvantage with this approach is that the compiler can't check whether the method really exists or not at compile time(Even if you have misspelled it).
EX:1
func buttonClicked(){
}
So the above method in the new approach can be called as #selector(buttonClicked)
EX:2
func buttonClicked(stringValue : String){
}
So the above method in the new approach can be called as #selector(buttonClicked(_:))
EX:3
func buttonClicked(stringValue : String, indexValue : Int){
}
So the above method with parameters in the new approach can be called as #selector(buttonClicked(_:indexValue:))
Consider below code for adding target to button in swift 3 using #selector
button.addTarget(self, action: #selector(self.buttonAction(sender:)),
for: UIControlEvents.touchUpInside)
func buttonAction(sender:UIButton!){
}
This syntax worked for me when migrating to swift 3
This is the way Swift method signatures are represented in documentation, and it is now beginning to be used in new language features such as the #selector() syntax to express methods by their argument lists.
The each colon (:) represents a method parameter. For named parameters, the colon is preceded by the external parameter name; for unnamed parameters, an underscore (_) is used.
So for example, MyVC.timerCalled(_:)) indicates a method on the MyVC type with one unnamed parameter, which might be declared like this:
func timerCalled(timer: NSTimer) { ... }
(Note that timer is the internal parameter name, since by default the first parameter of a method is unnamed)
The type (MyVC in your example) can also be omitted if it is within the same scope of the #selector() declaration.
A more complex example might look like this:
let sel = #selector(aMethodWithSeveralParameters(_:secondParam:thirdParam:))
...
func aMethodWithSeveralParameters(firstParam: Int, secondParam: Int, thirdParam: Int) { ... }
Related
Can anyone help me with this?
override func viewDidLoad() {
super.viewDidLoad()
tableView.delegate=self
tableView.dataSource=self
searchBar.autocorrectionType = .yes
searchBar.delegate=self
searchBarView.translatesAutoresizingMaskIntoConstraints=false
let tap:UIGestureRecognizer = UITapGestureRecognizer(target: self, action: Selector(("tapCancel:")))
searchBarView.addGestureRecognizer(tap)
tableView.addGestureRecognizer(tap)
tableView.isUserInteractionEnabled=true
}
...
func tapCancel(sender:UITapGestureRecognizer){
hideSearchBarView()
isSearchon=false
print("Tap cancel!")
}
Every time I tap the View, it crash.
"unrecognized selector sent to instance 0x7feb85d109e0"
I will appreciate any help!
Thanks!
I believe the reason is due to how method names get mapped between Swift and Objective-C, which underlies the Cocoa implementation and the whole target/action mechanism.
In your case, the Swift method:
#objc func tapCancel(sender:UITapGestureRecognizer)
...corresponds to the Objective-C selector:
-tapCancelWithSender:
Note: In order to work with the target/action paradigm (i.e., called by means of a selector), the method needs to be declared as #objc. The alternative attribute #IBOutlet (for use in conjunction with Interface Builder) also supports this. (tip of the hat to #rmaddy)
In order to remove the "withSender" part and get a selector that matches tapCancel:, you need to tell Swift to remove the argument label sender, like this:
func tapCancel(_ sender:UITapGestureRecognizer) // Notice the underscore (_)
Also, in line with the comment by #dan, perhaps you can use:
#selector(self.tapCancel(_:))
or more succinctly, as pointed by (thanks again) #rmaddy, just:
#selector(tapCancel)
(Xcode will try to autocomplete it to #selector(tapCancel(_:)), but the shorter syntax works as well and the method name is highlighted)
I was not familiar with the Selector() syntax you used, so I tried playing a bit with it, and behold:
(Selector does not match any method the compiler can "see").
(After adding "withSender", the compiler can match the method, but it suggests using the better #selector(... syntax).
As #rmaddy also pointed out in the comments, using the shorter #selector(doSomething) syntax (no colons, no underscore, no self) also does away with the problem of whether "withSender" is needed or not.
use
let tap:UIGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(tapCancel))
instead of
let tap:UIGestureRecognizer = UITapGestureRecognizer(target: self, action: Selector(("tapCancel:")))
And add #objc before method tapCancel()
In Swift 2, it appears that the first parameter name is not always required when calling a function. Now in Swift 3, the first parameter name is required when calling the function. For example:
func frobnicate(runcible: String) {
print("Frobnicate: \(runcible)")
}
Swift 2.2 allowed the function to be called by simply typing:
Frobnicate("Station")
Swift 3 seems to be requiring that we use the first parameter names of methods such as:
Frobnicate(runcible:"Station")
Is this the case with Swift 3 for all functions and methods or just certain situations?
Yes, this is right. Swift is fixing a language inconsistency this way (this was always required for initializers).
If you don't want to use the external parameter name, just remove it explicitly:
func frobnicate(_ runcible: String) {
print("Frobnicate: \(runcible)")
}
You can read the full rationale in Swift Evolution 0046
You can read The Swift Programming Language (Swift 3) in i-Book. Also you can check this out in WWDC 2016: What's New in Swift
In Swift 3, by default, functions use their parameter names as labels for their arguments. Write a custom argument label before the parameter name, or write _ to use no argument label.
fun greet(_ person: String, on day: String) -> String {
return "Hello \(person), today is \(day)."
}
greet("John", on: "Wednesday")
or
// This also works with Swift 2
fun addThreeNumber(_ first: Int, _ second: Int, _ third: Int) {
print(first+second+third)
}
addThreeNumber(1, 2, 3)
Exactly. In Swift 3.0, it's mandatory to write parameter names for all the parameters (including the first parameter). Parameter name is the one which is used inside the function implementation body.
func frobnicate(runcible: String) {
print("Frobnicate: \(runcible)")
}
By default, the external parameter label is same as the parameter name, if you don't specify any parameter label explicitly. Parameter label is the one which is used to pass the arguments while calling the function. If you need, for better clarity purpose, you can also specify external parameter labels explicitly. Example below-
func frobnicate(runcibleExternalLabel runcible: String) {
print("Frobnicate: \(runcible)")
}
If you want to skip the external parameter label while calling the function, just prepend a "_" before the parameter name.
func frobnicate(_ runcible: String) {
print("Frobnicate: \(runcible)")
}
Yes Swift 3 requires you to send First Parameter Label.
Please refer Swift 3 changes
The reason you want labels for parameters is so other code can supply parameters in any order.
Without labels, when you call the function the parameters are anonymous and you cannot be certain if you have supplied them in the wrong order.
Place labels in front of the parameters and code tools can do a much better job at catching errors us humans put in.
The underscore is just a way to cope with the transition from legacy code; method names including an Implicit first parameter. You should change any underscores that migration adds to your code to an explicit parameter label. You know it makes sense.
I am new to Swift and am confused with this type of syntax. I know when you add () to the end of something you initialize it. I am still confused what this means though! I am adding code below.
Please help clarify what parenthesis at the end of this means! Thank you!
Also what does it mean to have all that code after the equal sign in this case? ( I know how to create a variable and add a String,Int or something like that to it).
I am just confused a bit wth this code.
Thanks for being understanding to a beginner!
var viewController: ViewController = {
return self.instantiateViewControllerWithIdentifier("Play") as ViewController
}()
EDIT 1 -
var statusBarStyle: UIStatusBarStyle = .Default {
didSet{
setNeedsStatusBarAppearanceUpdate()
}
}
{} declares a closure, which is anonymous function. Everything between { and } is a function body. Since closure defined in provided code does not have arguments it can be executed as regular function by (). { .. }() is just defining and immediately executing of anonymous function.
In a body of a function there is a call of instantiateViewControllerWithIdentifier("Play") which returns AnyObject. As viewController variable (var) expected to ba a type of ViewController, we cast AnyObject result of instantiateViewControllerWithIdentifier as ViewController
As for statusBarStyle, UIStatusBarStyle is an enum. .Default is one of enum's cases. It can be written alternatively as var statusBarStyle = UIStatusBarStyle.Default. The code that goes in the { ... } is a way to declare getter and setter behavior. In this particular case there is only one behavior didSet defined, which means as soon as value of UIStatusBarStyle updated (which is possible, as it is var), call function setNeedsStatusBarAppearanceUpdate. There are other getters & setters keywords that you may read about in Swift Book — https://itunes.apple.com/us/book/swift-programming-language/id881256329 such as get, set, willSet.
As Nikita said its instantly calling the anonymous function you declared. This is really useful as it allows you to add logic when initialising a var or let.
Since the function takes no arguments, it makes it harder to see at first that it actually is a function. An example with an argument makes this concept a lot clearer.
let oneMore: Int = { (num: Int) in num + 1 }(5) //oneMore = 6
We are creating a function that takes one Int argument num and implicitly returns an Int (the compiler knows this because of the type annotation on oneMore. By following the closure with (5) we are calling the anonymous function with the value of 5.
Hopefully this example makes it more clear what happening. Note for an anonymous function in the context we would never need to provide argument since it will only ever be called once with the arguments following it, so we can just include the argument within the function body.
let oneMore: Int = { 5 + 1 }()
In the second example the braces are allowing you to include property observers to the variable. an example of a property observer is didSet which is called each time after you assign a value to the variable. more info can be found in apples docs here.
My Swift code has this:
#objc protocol MyDelegate {
func buttonPressed(buttonNum: Int, packet: Packet?)
}
Then my objective-c code for the delegate has this:
- (void)buttonPressed:(NSInteger)buttonNum :(Packet * _Nullable) packet {
}
But I'm getting a "function not implemented" warning. My experiments seem to indicate that there's something wrong with that nullable pointer. I.e. if there was no "?" in the Swift proto declaration and no "_Nullable" in the Object-c function then all is well.
Does anyone know what I need to do on the Objective-c side to implement that function for that proto?
The problem is not due to the nullability of the parameter, but due to the selector name.
func buttonPressed(buttonNum: Int, packet: Packet?)
should get a
buttonPressed:packet:
Objective-C function. Yours is buttonPressed:: - no label for the second parameter.
The confusion might have been caused by the fact that Swift automatically infers labels starting with the second parameter - if no label is specified, then the label is assumed to be the parameter name. This is why in Swift you'd need to call the protocol function as buttonPressed(arg1, packet: arg2).
Now you can either add the packet label to the Objective-C selector, or you can remove it from the Swift function declaration, like this:
func buttonPressed(buttonNum: Int, _ packet: Packet?)
You can then call it from Swift like buttonPressed(arg1, arg2). It's up to you which approach you choose, although I'd recommend going with the labeled one as is more clear, at least in Objective-C.
Given a function reference, is there a way in Swift to get the name of that function as a string suitable for passing to NSSelectorFromString?
I'd like to wrap NSNotificationCenter's addObserver with a version that takes a function reference instead of a selector string:
addObserver(self, function: someCallback, name: "some notification", object: nil)
But addObserver takes a String selector argument.
You're reinventing an unnecessary wheel. NSNotificationCenter already has an observation method that takes a function (what Objective-C calls a "block"):
addObserverForName:object:queue:usingBlock:
So just use that.
I'd still like to find an answer to my original question, but based on #matt's suggestion, I'm currently using this extension:
extension NSNotificationCenter {
class func addObserver(function: (NSNotification!) -> (), name: String? = nil, object: AnyObject? = nil, queue: NSOperationQueue? = nil) {
defaultCenter().addObserverForName(name, object: object, queue: nil, usingBlock: function)
}
}
Since it implicitly uses defaultCenter() and provides defaults for object and queue, which I'd almost always pass nil for, it allows for a more succinct call:
NSNotificationCenter.addObserver(doSomething, name: "some notification")
I like that it links against the actual function (doSomething), rather than a string representation. It's not a general purpose extension, but I think it covers 90% of the cases where I register for notifications.
Edit: I'm leaving this here for interest, but it's way too complicated (got wrapped up in how the question was asked, rather than the goal). Beyond the existing block-based approach, there's also this handy extension to it.
I wouldn't do it this way. It's too limiting because it would exclude function literals (anonymous functions).
Instead, I would play this game:
Create an dictionary property mapping [String: Void -> ()] (string to function)
When you register a new function, make up a unique, random key and store the function you're passed in your dictionary with that key.
Register with the selector observer_dispatcher_<key> (or whatever prefix you like).
Implement resolveInstanceMethod: to dynamically create any observer_dispatcher_ method you're requested. They can all point to the same IMP, something like:
(assuming this is good Swift; I haven't tried it):
void _observer_dispatcher(self: AnyObject, _cmd: Selector) {
let name = // strip the leading stuff off of _cmd
if let f = self.dispatchTable[name] {
f()
}
}
(This is still pretty sloppy; I'll have to think about the correct correct impl more, but this is the direction I'd go in.)