The #Selector Is Not Compatible with The Closure

The #selector is not compatible with the closure?

A selector is a string that's used to identify methods, properties, initializers in the Objective C runtime. When you use a notation like #selector(SomeClass.SomeMethod(withParam:AndParam:), you're specifying the selector in a format that the compiler can parse easily and verify to be correct. But ultimately, that would just be reduced down into a C string like: "SomeMethodwithParam:AndParam:".

Essentially, every class has a dictionary which maps selectors to the function pointers of the code that implements them. When a selector is used to invoke a function, the Objective C runtime searches the method table for the class in question, and looks up the method implementation corresponding to the given selector.

There's no way for this process to work with closures, which are anonymous by definition. Thus, you can only use selectors to refer to methods, properties, initializers that are registered with the Objective C runtime (which is what @objc does, implicitly or explicitly).

Can I make #selector refer to a closure in Swift?

As @gnasher729 notes, this is not possible because selectors are just names of methods, not methods themselves. In the general case, I'd use dispatch_after here, but in this particular case, the better tool IMO is UIView.animateWithDuration, because it's exactly what that function is for, and it's very easy to tweak the transition:

UIView.animateWithDuration(0, delay: 0.5, options: [], animations: {
self.view.backgroundColor = UIColor.whiteColor()
self.view.alpha = 1.0
}, completion: nil)

Closures for UIGestureRecognizers

Your problem is your target is on on the TapGestureRecognizer class itself. Your runAction method is an instance method, but you're telling the super.init that it's a class method, thus the failure here: +[MyApp.TapGestureRecognizer runAction]. You can fix this by making runAction a class method.

You could also remove the target on class and add the instance after initialization:

init() {
super.init(target: TapGestureRecognizer.self, action: #selector(runAction))
self.removeTarget(TapGestureRecognizer.self, action: #selector(runAction))
self.addTarget(self, action: #selector(runAction))
}

Or you could somehow wrap the closure to be fired in a different object.

Swift Selectors and Closures Discussion

In your case at the moment, it seems that no cyclic-reference is formed. But it's possible to accidentally be formed in the future. Like the followings for the instance.

// In the `Test` class.
let control = MyControl()
init() {
control.addClosureFor(UIControlEvents.TouchUpInside, closure: { (control) -> () in
self.testProperty = "This is making a reference cycle?"
})
}

In this code, self has a reference to the control as its field and the control has a reference to self through the closure added by addClosureFor. This forms a cyclic reference so these objects in the cycle are never released.

closure capture list helps this issue.

control.addClosureFor(UIControlEvents.TouchUpInside) { [weak self] /* <-- */ control -> () in
// Here, `self` is visible as `Optional<Test>` so the `?` operator is required.
self?.testProperty = "This is making a reference cycle?"
return
}

In the block in this code above, self is weakly captured so that an only one unidirectional reference is formed from self to the control.
Note that, now in the closure, the access to self isn't assured because self is weakly-referenced. You have to consider self an optional value.

https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/AutomaticReferenceCounting.html

How to use the not selector correctly in CSS

Your only issue is that you're passing two selectors inside the :not() use only one per statement.

Currently extended arguments (foo, bar) are not supported by any browser.

Use

:not(.class1):not(.class2)

https://developer.mozilla.org/en-US/docs/Web/CSS/%3Anot

input[type=text][readonly]:not(.class1):not(.class2) {  background-color: #DDDDDD;  color: #1E1E1E;}
<input type=text readonly class="class1"><input type=text readonly><input type=text readonly class="class2">

Argument of '#selector' does not refer to an '@objc' method, property or initializer

The selector of a target / action method must be declared either without parameter or with one parameter passing the affected object.

In case of a Timer use the userInfo parameter to pass data.

timer = Timer.scheduledTimer(timeInterval: 0.1, target: self, selector:#selector(updateTimer(_:)), userInfo: 3, repeats: true)   

func updateTimer(_ timer: Timer) {
let endTime = timer.userInfo as! Int
counter -= 1
timeLabel.text = String(counter)
if counter == endTime {
step += 1
}
}

If the enclosing class does not inherit form NSObject you have to add the @objc attribute to the action method.



Related Topics



Leave a reply



Submit