I have an Objective-C method like this:
-(void)findFiles{
}
It is working fine.But I need to call this method in Swift class.I have done :
var instanceOfCustomObject:DriveListTableViewController = DriveListTableViewController()
and now I can use the method like this:
instanceOfCustomObject.find()
But it works only in if I place it into viewDidLoad.
Is there a way that I can call it on click of button?
I have created button
let button:UIButton = UIButton(frame: CGRect(x: 100, y: 400, width: 100, height: 50))
button.backgroundColor = .black
button.setTitle("Button", for: .normal)
button.addTarget(self, action:#selector(self.buttonClicked), for: .touchUpInside)
self.view.addSubview(button)
func buttonClicked() {
print("Button Clicked")
instanceOfCustomObject.findFiles()
}
But it still works only if I place it into viewDidLoad. Please help me! Is there any other way to make it call in Swift file from Objective-C file??
Declare your var instanceOfCustomObject outside the viewDidLoad method (i.e., inside the class but outside the method).
Related
addTarget
So I know that you can use addTarget on a button
like so:
import UIKit
class ViewController: UIViewController {
func calledMethod(_ sender: UIButton!) {
print("Clicked")
}
override func viewDidLoad() {
super.viewDidLoad()
let btn = UIButton(frame: CGRect(x: 30, y: 30, width: 60, height: 30))
btn.backgroundColor = UIColor.darkGray
btn.addTarget(self, action: #selector(self.calledMethod(_:)), for: UIControlEvents.touchUpInside)
self.view.addSubview(btn)
}
}
This works absolutely fine but I was just wondering is there another way to detect when something is clicked and run some code when that happens.
You can add button in the storyboard and create an outlet for it's action.
#IBAction func buttonAction(_ sender: UIButton) {
//implement your code here
}
A button is a subclass of UIControl. A UIControl is designed to use target/action to specify code to run when the specified action occurs. If you don't want to use that mechanism, you have to create an equivalent.
You could attach a tap gesture recognizer to some other object and set it's userInteractionEnabled flag to true, but gesture recognizers ALSO use the target/action pattern.
My suggestion is to "stop worrying and learn to love the button." Just learn to use target/action.
Another possibility: Create a custom subclass of UIButton that sets itself up as it's own target at init time (specifically in init(coder:) and init(frame:), the 2 init methods you need to implement for view objects.) This button would include an array of closures that its action method would execute if the button was tapped. It would have methods to add or remove closures. You'd then put such a button in your view controller and call the method to add the closure you want.
You can also have a look at RxSwift/RxCocoa or similar. All the changes and actions are added automatically and you can decide if you want to observe them or not.
The code would look something like this:
let btn = UIButton(frame: CGRect(x: 30, y: 30, width: 60, height: 30))
btn.backgroundColor = UIColor.darkGray
btn
.rx
.tap
.subscribe(onNext: {
print("Clicked")
}).disposed(by: disposeBag)
view.addSubview(btn)
I have created a button programatically and want to add a touch event handler. I have tried all the tricks I have found online but the desired function is just never triggered.
upgradeNowView = UIButton()
upgradeNowView.setTitle("Upgrade", forState: .Normal)
upgradeNowView.contentMode = UIViewContentMode.ScaleToFill
upgradeNowView.frame = CGRect(x: upgradeNowView.frame.minX, y: -50 , width: 320, height: 50)
upgradeNowView.userInteractionEnabled = true
upgradeNowView.sendActionsForControlEvents(.TouchUpInside)
upgradeNowView.addTarget(self, action: #selector(MainViewContainer.upgradeTapped(_:)), forControlEvents: .TouchUpInside)
side_menu_controller?.view.addSubview(upgradeNowView)
and defined this
func upgradeTapped(sender: UIButton)
{
UpgradeViewController.openUpgrade()
}
But this just never gets called. Any help would be appreciated.
You need to define upgradeTapped function in class of side_menu_controller instance. I guess, it's SideMenuController class.
I found out this was caused by the fact that I was placing the button next to the view but outside its bounds (just on top):
upgradeNowView.frame = CGRect(x: upgradeNowView.frame.minX, y: -50 , width: 320, height: 50)
There are two ways around this:
Move the button inside the bounds of the parent view, or
Handle touches outside the view by overriding "hitTest" as discussed here
Using pod 'Player' in an iOS 9.0 app to play a video. I've subclassed Player class to add a UIButton overlay for closing the window.
It appears fine and has highlighting animation when tapped, but closeTapped isn't called when touching up inside.
import UIKit
import Player
class PlayerViewController: Player, PlayerDelegate {
func install() {
view.frame = presentor.view.bounds
presentor.addChildViewController(self)
presentor.view.addSubview(view)
didMove(toParentViewController: presentor)
let closeImage = UIImage(named: "close")!
let closeButton = UIButton(type: .custom)
view.addSubview(closeButton)
closeButton.setImage(closeImage, for: .normal)
closeButton.autoPinEdge(toSuperviewEdge: .top, withInset: 25)
closeButton.autoPinEdge(toSuperviewEdge: .right, withInset: 15)
closeButton.autoSetDimensions(to: CGSize(width: 50, height: 50))
closeButton.addGestureRecognizer(UITapGestureRecognizer())
closeButton.addTarget(self, action: #selector(closeTapped), for: .touchUpInside)
}
func closeTapped() {
logger.debug("Player close tapped")
}
}
I also tried having closeTapped(sender: Any?), didn't help.
Why isn't closeTapped called?
You don't need to add a TapGestureRecognizer to the button. For swift 3.0 you can do it like this:
button.addTarget(self, action: #selector(closeTapped(sender:)), for: .touchUpInside)
func closeTapped(sender: UIButton) {
}
I think the top of your button u added a UITapGestureRecognizer(). Which itself has a #selector. So Your button default .touchUpInside controller is not calling.
Try with commenting
//closeButton.addGestureRecognizer(UITapGestureRecognizer())
this line.
Let me know is this helpful or not.
I've had this issue before but it usually due to not having a button hooked up in Storyboard or not passing a parameter when the function is expecting one, like most of the existing questions on here seem to suggest. This time however it is neither of those things.
I am creating a button in my TableView Cell by using this code in the CellForRowAt method:
let button = UIButton(frame: CGRect(x: 0, y: 0, width: 100, height: 50))
button.addTarget(self, action: Selector(("showPeople:")), for: UIControlEvents.touchUpInside)
button.tag = indexPath.row
cell.addSubview(button)
and I have declared the showPeople method like so:
func showPeople(sender: UIButton) {
print("pressed")
}
When the button is pressed the program crashed with the following message:
showPeople: unrecognized selector sent to instance
But when I declare the method like so (remove the parameter):
func showPeople() {
print("pressed")
}
and change the selector to Selector(("showPeople")) it works fine which I guess means there is an issue with the way I'm passing the parameter. Why would this be happening? The function is expecting a parameter so the : is needed.
Looks like you're missing sender part in your selector.
Try this instead:
button.addTarget(self, action: #selector(ViewController.showPeople(sender:)), for: .touchUpInside)
When I first run my app, I retrieve a number from my server and display it for my UIButton label. Think of this as a notification number displayed on a red UIButton.
When I remove a notification within the app, I want my UIButton label decrement by 1. I am able to get the decremented number from the server after I delete a notification, but I can't display this new number on the UIButton. The button always displays the number when the app is first fired.
I call makeButtonView() method after I remove a notification to update the UIButton
func makeButtonView(){
var button = makeButton()
view.addSubView(button)
button.tag = 2
if (view.viewWithTag(2) != nil) {
view.viewWithTag(2)?.removeFromSuperview()
var updatedButton = makeButton()
view.addSubview(updatedButton)
}else{
println("No button found with tag 2")
}
}
func makeButton() -> UIButton{
let button = UIButton(frame: CGRectMake(50, 5, 60, 40))
button.setBackgroundImage(UIImage(named: "redBubbleButton"), forState: .Normal)
API.getNotificationCount(userID) {
data, error in
button.setTitle("\(data)", forState: UIControlState.Normal)
}
button.addTarget(self, action: "targetController:", forControlEvents: UIControlEvents.TouchUpInside)
return button
}
Use this code for Swift 4 or 5
button.setTitle("Click Me", for: .normal)
I need more information to give you a proper code. But this approach should work:
lazy var button : UIButton = {
let button = UIButton(frame: CGRectMake(50, 5, 60, 40))
button.setBackgroundImage(UIImage(named: "redBubbleButton"), forState: .Normal)
button.addTarget(self, action: "targetController:", forControlEvents: UIControlEvents.TouchUpInside)
return button
}()
func makeButtonView(){
// This should be called just once!!
// Likely you should call this method from viewDidLoad()
self.view.addSubview(button)
}
func updateButton(){
API.getNotificationCount(userID) {
data, error in
// be sure this is call in the main thread!!
button.setTitle("\(data)", forState: UIControlState.Normal)
}
}
There have been some updates since Swift 4. This works for me:
self.button.setTitle("Button Title", for: UIControl.State.init(rawValue: 0))
Replace button with your IBOutlet name. You can also use a variable or array in place of the quoted text.
It's fairly simple ...
import UIKit
class ViewController: UIViewController {
#IBOutlet var button: UIButton!
override func viewDidLoad() {
super.viewDidLoad()
button.setTitle("hello world", forState: UIControlState.Normal)
}
}
I believe if you set the state to normal, the value will propagate by default to other states so long as you haven't explicitly set a title for those states.
Said differently, if you set it for normal, it should also display this title when the button enters additional states
UIControlState.allZeros
UIControlState.Application
UIControlState.Disabled
UIControlState.Highlighted
UIControlState.Reserved
UIControlState.Selected
Lastly, here's Apple's documentation in case you have other questions.
Since your API call should be running on a background thread you need to dispatch your UI update back to the main thread like this:
DispatchQueue.main.async {
button.setTitle(“new value”, forState: .normal)
}
After setting the title, just a simple redraw of the button will do:
button.setNeedsDisplay();