Value of type 'CustomButton' has no member 'touchDown' - uibutton

I have created custom button class and override all touches methods. It works fine in swift 2 and Xcode 7.3.1. But when I open same app in Xcode 8.0, it will show errors :
Value of type 'CustomButton' has no member 'touchDown'
Value of type 'CustomButton' has no member 'touchUpInside'
Value of type 'CustomButton' has no member 'touchDragExit'
Value of type 'CustomButton' has no member 'touchDragEnter'
Value of type 'CustomButton' has no member 'touchCancel'
Here is my code :
import UIKit
#IBDesignable
#objc public class CustomButton: UIButton {
private func addTargets() {
//------ add target -------
self.addTarget(self, action: #selector(self.touchDown(_:)), for: UIControlEvents.TouchDown)
self.addTarget(self, action: #selector(self.touchUpInside(_:)), for: UIControlEvents.TouchUpInside)
self.addTarget(self, action: #selector(self.touchDragExit(_:)), for: UIControlEvents.TouchDragExit)
self.addTarget(self, action: #selector(self.touchDragEnter(_:)), for: UIControlEvents.TouchDragEnter)
self.addTarget(self, action: #selector(self.touchCancel(_:)), for: UIControlEvents.TouchCancel)
}
func touchDown(sender: CustomButton) {
self.layer.opacity = 0.4
}
func touchUpInside(sender: CustomButton) {
self.layer.opacity = 1.0
}
func touchDragExit(sender: CustomButton) {
self.layer.opacity = 1.0
}
func touchDragEnter(sender: CustomButton) {
self.layer.opacity = 0.4
}
func touchCancel(sender: CustomButton) {
self.layer.opacity = 1.0
}
}
If anyone have any solution, please let me know.

If you want to keep your method headers as are in your code, you need to change the selector references to #selector(touchDown(sender:)), and so on.
(Generally, you have no need to prefix self..)
Remember all functions and methods now have consistent label treatment for their first parameters. SE-0046
(You may find many good articles, searching with "swift3 selector".)
If you want to keep the selector references, you need to change the methods like:
func touchDown(_ sender: CustomButton) {
For addition, #selector(touchDown) would work, if your class has only one touchDown(...) method.

I have found solution as #OOPer suggested, but there also need to change UIControlEvents in small case. In Xcode 7.3.1 it was UIControlEvents.TouchDown but now it has to be UIControlEvents.touchDown.
It will be like :
self.addTarget(self, action: #selector(touchDown(sender:)), for: UIControlEvents.touchDown)
self.addTarget(self, action: #selector(touchUpInside(sender:)), for: UIControlEvents.touchUpInside)
self.addTarget(self, action: #selector(touchDragExit(sender:)), for: UIControlEvents.touchDragExit)
self.addTarget(self, action: #selector(touchDragEnter(sender:)), for: UIControlEvents.touchDragEnter)
self.addTarget(self, action: #selector(touchCancel(sender:)), for: UIControlEvents.touchCancel)

Related

Swift selector method not being called

I create an action class to store the selectors, then addTarget to the button, but when I click it, the method in the action class has not been called
class ItemCardAction {
static var shared: ItemCardAction = ItemCardAction()
private init() {
}
var action: Selector = #selector(ItemCardAction.shared.buttonPressed)
#objc func buttonPressed(_ sender: UIButton!) {
print("TEST")
AppEngine.shared.updateItem(tag: sender.tag)
AppEngine.shared.notigyAllObservers()
//self.updateUI()
}
}
add target
button.addTarget(self, action: ItemCardAction.shared.action, for: .touchDown)
What you need is
button.addTarget(ItemCardAction.shared, action: ItemCardAction.shared.action, for: .touchUpInside)
If you look at addTarget method carefully, the first argument is target, when button receives (in this specific case) a touch inside event, iOS will look for the specified selector (specified in action parameter) in target specified. In your case you specified the target as self and clearly selector is not available in self's scope hence nothing happens :)

Conforming to a Obj-C protocol in Swift [duplicate]

Ok here is the big problem. I had a library written in ObjC(this). There we had a defined protocol. When I tried to use it in swift file I get constantly:
Type "XXX" does not conform to protocol "XXX"
To simplify things I made up a test project - it should be created as Swift project.
Then create ObjC header file(I called it StupidProtocol.h) with following protocol inside(please note each name and value to exactly match the given including uppercase/lowercase):
#protocol MyProtocol <NSObject>
- (NSString *)getAxisLabel:(id)axis Value:(CGFloat)value;
#end
In bridging header:
#import "StupidProtocol.h"
And then back in Swift file:
class ViewController: UIViewController, MyProtocol
{
func getAxisLabel(axis: AnyObject!, value: CGFloat) -> String! {
return ""
}
}
And baam we got this error again even though auto-complete finishes the getAxisLabel function for me.
I strongly suspect that the problem is with argument "value" and it's function parameter "Value".
Any help will be highly appreciated.
EDIT
Please note that this library is not technically mine, so I cannot change it. I need a way to use it in Swift without changing it's original declaration. My example is only to simplify my problem.
WHAT I TRIED
I have tried following scenarios with no success:
'has different arguments name from those required by protocol' error
func getAxisLabel(axis: AnyObject!, Value value: CGFloat) -> String! {
return ""
}
'has different arguments name from those required by protocol' error
func getAxisLabel(axis: AnyObject!, Value: CGFloat) -> String! {
return ""
}
'type does not conform to protocol'
func getAxisLabel(axis: AnyObject!, Value: CGFloat) -> NSString! {
return ""
}
SOLUTION
See accepted answer
I don't know if this is a bug or not. The Objective-C protocol method
- (NSString *)getAxisLabel:(id)axis Value:(CGFloat)value;
(with uppercase "V" in Value:) is mapped to Swift as
func getAxisLabel(axis: AnyObject!, value: CGFloat) -> String!
(with lowercase "v" in value:), but none of
func getAxisLabel(axis: AnyObject!, value: CGFloat) -> String! { }
func getAxisLabel(axis: AnyObject!, Value: CGFloat) -> String! { }
is accepted by the compiler to satisfy the protocol requirement.
As a workaround, you can annotate the method with an explicit
Objective-C selector name:
class ViewController: UIViewController, MyProtocol
{
#objc(getAxisLabel:Value:)
func getAxisLabel(axis: AnyObject!, value: CGFloat) -> String! {
return ""
}
}

Having a function argument of type "Selector" in a Swift class will render the function unavailable to Objective-C

When trying to use the Menu class below from my Objective-C code, I'm only able to access foobar (or any other function that does not have the Selector type in the argument list), while the addItemWithName function is unavailable (I have checked the autogenerated swift to objective-c file and the function is not listed in the Menu interface there). How can I make this work?
public class Menu : UIView {
public func foobar() {
// implementation
}
public func addItemWithName(itemName: String, target: AnyObject?, action: Selector?) {
// implementation
}
}
The problem type isn't Selector, it's Selector?. You can't express Optional<Selector> in ObjC because SEL is not an object type.

Swift 2.1: Property cannot be marked dynamic?

How do I fix this compilation error?
dynamic var users = [User]()
Property cannot be marked dynamic because its type cannot be represented in Objective-C
I need dynamic so that certain view controllers can observe (via KVO) users and update their views when users changes.
Just as the error mentions
error, not #objc : NSObject:
class A{
}
func something(){
dynamic var a = [A]()
}
should be changed to:
#objc class A:NSObject{
}
func something(){
dynamic var a = [A]() //works, all good
}

iCarousel in swift version 1.2 error (candidate is not Objc but protocol requires it)

I get the following error in swift 1.2 : 'RootViewController' does not conform to protocol 'iCarouselDataSource'
In the below class, when I tryed to implement the third party library iCarousel:
class RootViewController: UIViewController,iCarouselDataSource,iCarouselDelegate
{...}
The auto-fix tool puts an #objc mark in this method that conform the protocol:
#objc func carousel(carousel: iCarousel!, viewForItemAtIndex index: Int, var reusingView view: UIView?) -> UIView?
{}
But then another error appears : Method cannot be marked #objc because the type of the parameter 3 cannot be represented in Objective-C
I appreciate any help or clue, thanks !
Remove var from reusingView, ex:
func carousel(carousel: iCarousel!, viewForItemAtIndex index: Int, reusingView view: UIView!) -> UIView! {
var newView = view
if newView == nil {
//create new view
}
//update data
return newView
}