Can you addTarget to UIButton in NSObject class? - ios

How do you addTarget to a UIButton in an NSObject class? Or will that class not work?
class Support: NSObject {
func helpButton(viewController: ProfileVC) {
let helpButton = viewController.helpButton
helpButton.frame.size = CGSizeMake(35.0, 35.0)
helpButton.layer.cornerRadius = helpButton.frame.height/2
helpButton.layer.borderWidth = 0.5
helpButton.layer.borderColor = lightColoredFont.CGColor
helpButton.setTitle("?", forState: .Normal)
helpButton.setTitleColor(lightColoredFont, forState: .Normal)
helpButton.titleLabel?.font = fontSmaller
helpButton.addTarget(self, action: Selector("showOptions"), forControlEvents: .TouchUpInside)
helpButton.center.y = viewController.logoutButton.center.y
helpButton.frame.origin.x = (viewController.view.bounds.width - viewController.logoutButton.frame.maxX)
viewController.view.addSubview(helpButton)
}
func showOptions() {
print("showing")
}
}
The print is not showing. Even if I feed an instantiated support class into the target for the button it will not work. What is the proper way to do this?

In short, no.
NSObject does not inherit from anything in UIKit. Your inheritance should be the other way around. Perhaps you could make a UIButton that has a property of type NSObject to carry some accompanying information?

Look at the UIControl API
func addTarget(_ target: AnyObject?,
action action: Selector,
forControlEvents controlEvents: UIControlEvents)
But what are you trying to do? Normally you would add a button in interface builder and a reference (IBOutlet) to that button from some controller class like UIViewController.
edit
Ah, now I see the problem. Don't use Selector in swift.
This should work.
helpButton.addTarget(self, action: "showOptions", forControlEvents: .TouchUpInside)

Related

Pass parameters to button action in swift

When setting the action with the "addTarget" method on a button in Swift, is there a way for me to pass a parameter to the function I want to trigger?
Say I had a simple scenario like this:
let button = UIButton()
button.addTarget(self, action: #selector(didPressButton), for: .touchUpInside)
#objc func didPressButton() {
// do something
}
Obviously the above code works fine, but say I wanted the 'didPressButton' function to take in a parameter:
#objc func didPressButton(myParam: String) {
// do something with myParam
}
Is there a way I can pass a parameter into the function in the 'addTarget' method?
Something like this:
let button = UIButton()
button.addTarget(self, action: #selector(didPressButton(myParam: "Test")), for: .touchUpInside)
#objc func didPressButton(myParam: String) {
// do something with myParam
}
I'm coming from a JavaScript background and in JavaScript it's pretty simple to achieve this behavior by simply passing an anonymous function that would then call the 'didPressButton' function. However, I can't quite figure how to achieve this with swift. Can a similar technique be used by using a closure? Or does the '#selector' keyword prevent me from doing something like that?
Thank you to anyone who can help!
The short answer is no.
The target selector mechanism only sends the target in the parameters. If the string was a part of a subclass of UIbutton then you could grab it from there.
class SomeButton: UIButton {
var someString: String
}
#objc func didPressButton(_ button: SomeButton) {
// use button.someString
}
It is not possible to do that in iOS. You can get the View in the selector in your case it is a button.
button.addTarget(self, action: #selector(buttonClick(_:)), for: .touchUpInside)
#objc func buttonClick(_ view: UIButton) {
switch view.titleLabel?.text {
case "Button":
break
default:
break
}
}

Swift addTarget to a button and call function in different View Controller file from UIview file

now I practice applying the MVC pattern in my Swift project.
I have one View Controller (VC) file and one UIView file.
In the VC file, I added the UIView file like below.
class MyViewController: UIViewController {
private var myView = MyView()
override func viewDidLoad() {
super.viewDidLoad()
view.addSubview(myView)
myView.frame = CGRect(origin: .zero, size: view.bounds.size)
// and other codes...
}
#objc func showDeleteAlert() {
print("showDelete is pressed")
}
}
Then, inside the UIView file, I added some views and buttons (I just copy the button part).
class MyView: UIView {
lazy var deleteButton: UIButton = {
let button = UIButton()
button.setTitle("delete", for: .normal)
button.addTarget(target: MyViewController, action: #selector(showDeleteAlert), for: UIControl.Event.touchUpInside) // -> I get error in here saying "Cannot find 'showDeleteAlert' in scope"
return button
}()
// and more codes...
}
What I want to do here is how to set the target to showDeleteAlert function when the deleteButton is pressed?
I saw tutorials add "self" as a target argument, but in my case, I separated view and controller so not really sure how to access the function in MyViewController.
Thank you...
You have two options here:
move addTarget into view controller viewDidLoad:
myView.deleteButton.addTarget(self, action: #selector(showDeleteAlert), for: UIControl.Event.touchUpInside)
If you wanna make button private(which is a good practice), you can add proxy func to your MyView
func addDeleteButtonTarget(_ target: Any?, action: Selector) {
deleteButton.addTarget(target, action: action, for: .touchUpInside)
}
And call it:
myView.addDeleteButtonTarget(self, action: #selector(showDeleteAlert))
In any case, you cant call button.addTarget(target: MyViewController, ...), because you need to pass an instance of the MyViewController, not just a class name.

addTarget from external class

I am facing this problem: I would like to assign an action for a button created runtime, I'm using this custom class:
import UIKit
class SubViewManager: NSObject {
var button = UIButton()
Then I have the function to add the button in the view:
frame.addSubview(button)
And the function for assign the action:
func setButtonAction(sender: UIButton!, buttonAction: Selector) {
button.addTarget(self, action: buttonAction, forControlEvents: UIControlEvents.TouchUpInside)
}
Now in the ViewController Class I call the SubViewManager object like this:
var newSubView:SubViewManager!
Then in a procedure I'm doing:
newSubView.addButton(...//Dimension and details//...)
newSubView.setButtonAction(newSubView.button, buttonAction: "save")
And here I have the problem, this error appair in the console:
unrecognized selector sent to instance 0x7f92f9694140
What I am doing wrong?
EDIT: I noticed that if I initialize the object directly in the function where I call the .setButtonAction it works, but I can't declare in the same function because I need it in multiple functions!
RE-EDIT: When i do the .addTarget method I would like to run a ViewController Class's procedure but it runs the SubViewManager procedure which don't exist, that's the why of the error, but I don't know how to run the ViewController Class procedure while calling the .addTarget in an external class.
its crashing because in your code the target that you set to handle the button's action event is the SubViewManager instance ('self' inside setButtonAction method)
func setButtonAction(sender: UIButton!, buttonAction: Selector) {
button.addTarget(self, action: buttonAction, forControlEvents: UIControlEvents.TouchUpInside)
}
But the actually object where you implemented the save function is ViewController class.
You can try modify the parameter of the setButtonAction method to pass the target that will implemented the button action instead of unused sender : UIButton! because you already call addButton method and has button property to point to it already.
Try something like this
func setButtonAction(target: AnyObject! , buttonAction: Selector) {
button.addTarget(target, action: buttonAction, forControlEvents: UIControlEvents.TouchUpInside)
}
Then pass in the viewController when you calling the setButtonAction method
newSubView.setButtonAction(self, buttonAction: "save")
where self is instance of the ViewController class that implemented the save function.

swift: Adding an action to an array of buttons

I'm designing a simple Sudoku app and need to trigger an action when any one of the 81 buttons are clicked. I created an array of UIButtons in my ViewController:
class SudokuBoardController : UIViewController {
#IBOutlet var collectionOfButtons: Array<UIButton>?
override func viewDidLoad() {
collectionOfButtons.addTarget(self, action: "buttonClicked:", forControlEvents: UIControlEvents.TouchUpInside)
...
}
}
I'm able to add the buttons to the Array from the storyboard ok, its just when I try to addTarget I get this message:
Value of type 'Array<UIButton>?' has no member addTarget
Is there a solution to this problem that does not involve me creating 81 different outputs for each button?
Thanks for your help!
Cheers
You have an Array, so you want to iterate over the UIButtons in the array. And because you're in Swift, you'll want to do so in a Swifty way, not using a simple for loop.
collectionOfButtons?.enumerate().forEach({ index, button in
button.tag = index
button.addTarget(self, action: "buttonClicked:", forControlEvents: .TouchUpInside)
})
This also nicely handles the fact that collectionOfButtons is an optional by doing nothing if it is nil, as opposed to crashing.
You need to iterate through array of buttons and add target to each of the button. Try out following code
var index = 0
for button in collectionOfButtons! {
button.tag = index // setting tag, to identify button tapped in action method
button.addTarget(self, action: "buttonClicked:", forControlEvents: UIControlEvents.TouchUpInside)
index++
}

Create custom button with Swift by extending the UIButton class

I'm in the process of learning Swift and I have a basic question. I don't want to use a Storyboard and I want to create a button with code. At the moment, I code my button this way:
let button1: UIButton = UIButton.buttonWithType(UIButtonType.Custom) as UIButton
button1.setImage(UIImage(named: "myImage.png"), forState: UIControlState.Normal)
button1.addTarget(self, action: "myMethod", forControlEvents: UIControlEvents.TouchUpInside)
button1.frame = CGRectMake(0, 0, 25, 25) // then I add this button to a navigation control
This works, but I'm looking for something slightly different. That is: I want to create a class, I want to pass at least the image name, the method the button must call and the frame. Moreover, I want to instantiate the button in my ViewController whenever I want.
I found many posts here but no post was really useful (some code did not work).
Can you help me?
enum SPBarButtonTypes {
case openDrawer
case loginInfo
}
class SPBarButtonFactory: NSObject {
class func createBarButtonItemOfType (buttonType: SPBarButtonTypes, withTarget buttonTarget: AnyObject, andAction buttonAction: Selector) -> UIBarButtonItem {
var returnButton: UIBarButtonItem = UIBarButtonItem()
returnButton.target = buttonTarget
returnButton.action = buttonAction
switch buttonType {
case .openDrawer:
returnButton.image = UIImage(named: "ic_menu")
case .loginInfo:
returnButton.image = UIImage(named: "ic_info_outline")
default: NSLog("Wrong BarButton type")
}
return returnButton
}
}
ADDED TO IMPROVE COMMENT
It just "seams" like a class nested in another class, but it really is Swifts way to declare a class-method....
This line declares a class named SPBarButtonFactory
class SPBarButtonFactory...
This line declares a class-method of SPBarButtonFactory
class func createBarButtonItemOfType...

Resources