RxSwift not working with UIButton - ios

I am working on RxSwift and started creating few basic. I have added new button however with rx_tap subscribe not working for button action. Below is my code, please let me know what I am doing wrong
let button = UIButton(frame: CGRect(x: 10, y: 66, width: 100, height: 21))
button.backgroundColor = UIColor.redColor()
button.setTitle("Login", forState: UIControlState.Normal)
let disposeBag = DisposeBag()
button.rx_tap
.subscribe { [weak self] x in
self!.view.backgroundColor = UIColor.redColor()
}
.addDisposableTo(disposeBag)
self.view.addSubview(button)

Your subscription is cancelled immediately because of the scope of your DisposeBag. It is created, then goes out of scope and immediately deallocated. You need to retain your bag somewhere. If you are using a view controller or something like that, you can create a property there and assign it to that.

Related

"Use of unresolved indentifier 'self'" with button.addTarget

I am a beginner to Swift. I have created a very simple button component, but when I try to add a function that is tied to the button click, I get the error: "Use of unresolved identifier 'self.'" Here is my code:
import UIKit
import PlaygroundSupport
let containerView = UIView (frame: CGRect(x: 0, y: 0, width: 600, height: 600))
containerView.backgroundColor = UIColor.blue
let button = UIButton (frame: CGRect(x: 100, y: 100, width: 200, height: 200))
button.backgroundColor = UIColor.yellow
button.setTitle("Test Button", for: .normal)
button.setTitleColor(.red, for: .normal)
button.layer.cornerRadius = 10
func ButtonClicked(_ sender: UIButton) {
print()
}
button.addTarget(self, action: #selector(ButtonClicked), for: .touchUpInside)
containerView.addSubview(button)
PlaygroundPage.current.liveView = containerView
Any help would be appreciated greatly, thanks!
As mentioned in the comments, there is no self to reference in your code as you're not working within a class or struct. The first thing you'll want to do is to wrap this stuff up into a class, and reorganize it a bit. I'd suggest going back to Xcode and doing the following:
File > New > Playground…
Select iOS > Single View
Save this new Playground somewhere.
Now, you should have a simple Playground created from a template. Here, you'll be able to see how a new class called MyViewController that inherits from UIViewController is created. Within that, you'll find a function called loadView(). Then, outside the class, you'll see where this new view controller is created and placed into the PlaygroundPage's current liveView.
Ideally, you should be able to click the Play button at the bottom of the code view, and if the Assistant editor is open, you'll see a simple view with a "Hello World!" label in the center of the view. (The assistant button is the one with the two interlocking circles.)
Assuming that runs and works for you, then I'd suggest you start adding your code back in and try to follow the patterns setup in the template. Place your code that sets up the view in the loadView() function, and move the ButtonClicked() function outside of that, but still within the class.
With a few modifications, you should be able to get up and running, and start playing around with Swift. As an example, here's a working version of your Playground code:
//: A UIKit based Playground for presenting user interface
import UIKit
import PlaygroundSupport
class MyViewController : UIViewController {
override func loadView() {
let containerView = UIView (frame: CGRect(x: 0, y: 0, width: 600, height: 600))
containerView.backgroundColor = UIColor.blue
let button = UIButton (frame: CGRect(x: 100, y: 100, width: 200, height: 200))
button.backgroundColor = UIColor.yellow
button.setTitle("Test Button", for: .normal)
button.setTitleColor(.red, for: .normal)
button.layer.cornerRadius = 10
button.addTarget(self, action: #selector(ButtonClicked), for: .touchUpInside)
containerView.addSubview(button)
self.view = containerView
}
#objc func ButtonClicked(_ sender: UIButton) {
print("ButtonClicked")
}
}
PlaygroundPage.current.liveView = MyViewController()
Have fun, spend some quality time with the Swift Programming Guide, and things'll start to make sense soon enough.

Fixing "use of unresolved identifier 'addTarget'" while adding func to button click event

I've created a UIButton programmatically as shown below:
let buttons: [UIButton] = [UIButton(frame: CGRect(x: 0, y: 0, width: 50, height: 50))];
Now if I try to add a function to it programmatically like this:
[buttons[0] addTarget:self action:#selector(buttonClicked:)forControlEvents:UIControlEventTouchUpInside]
I get an error saying that addTarget is not defined.
How do I fix this?
you are try to use the Objective-C syntax in swift, this is entirely wrong, use your code as like
buttons.first?.addTarget(self, action: #selector(self.buttonClicked(_:)), for: .touchUpInside)
and handle the action as like
#objc func buttonClicked( _ sender: UIButton) {
print("buttonClicked Action Found")
}
Ref : Apple Document for UIButton
First of all you are creating [UIButton] which is Array of UIButton and it's not a single Button.
You can not create Array of UIButton that way. You will need a for loop for that and you need to update the frame accordingly.
And you can create a single UIButton this way:
let button = UIButton(frame: CGRect(x: 0, y: 0, width: 50, height: 50))
then you can add it into the UIView this way:
self.view.addSubview(button)
Without above line it your button will not show into your screen.
Next if you want to add action to that button you can do it by adding this line in your button code:
button.addTarget(self, action: #selector(buttonClicked), for: .touchUpInside)
and it will need a helper method which will execute when button will click.
#objc func buttonClicked(_ sender: UIButton) {
//Perform your action when button is clicked.
}
And you also need to apply backgroundColor and setTitle to the button.
and your final code will look like:
let button = UIButton(frame: CGRect(x: 100, y: 100, width: 100, height: 50))
button.backgroundColor = UIColor.green
button.setTitle("Test Button", for: .normal)
button.addTarget(self, action: #selector(buttonClicked), for: .touchUpInside)
self.view.addSubview(button)

Eliminate repeated code Swift 3

I have multiple navigation controllers and their root view controllers in my app. I want each navigation bar to have social media buttons closely placed on the right side of the bar. For the same I have used this code to show the buttons in 1 view controller:
let fbImage = UIImage(named: "Facebook.png")!
let twitterImage = UIImage(named: "Twitter.png")!
let youtbImage = UIImage(named:"YouTube.png")!
let fbBtn: UIButton = UIButton(type: .custom)
fbBtn.setImage(fbImage, for: UIControlState.normal)
fbBtn.addTarget(self, action: #selector(HomeViewController.fbBtnPressed), for: UIControlEvents.touchUpInside)
fbBtn.frame = CGRect(x: 0, y: 0, width: 30, height: 30)
let fbBarBtn = UIBarButtonItem(customView: fbBtn)
let twitterBtn: UIButton = UIButton(type: .custom)
twitterBtn.setImage(twitterImage, for: UIControlState.normal)
twitterBtn.addTarget(self, action: #selector(HomeViewController.twitterBtnPressed), for: UIControlEvents.touchUpInside)
twitterBtn.frame = CGRect(x: 0, y: 0, width: 30, height: 30)
let twitterBarBtn = UIBarButtonItem(customView: twitterBtn)
let youtbBtn: UIButton = UIButton(type: .custom)
youtbBtn.setImage(youtbImage, for: UIControlState.normal)
youtbBtn.addTarget(self, action: #selector(HomeViewController.youtubeBtnPressed), for: UIControlEvents.touchUpInside)
youtbBtn.frame = CGRect(x: 0, y: 0, width: 30, height: 30)
let youtbBarBtn = UIBarButtonItem(customView: youtbBtn)
self.navigationItem.setRightBarButtonItems([youtbBarBtn, twitterBarBtn, fbBarBtn], animated: false)
Now I want the same buttons on all navigations bars. I can easily copy this code and respective target methods in viewDidLoad() of each view controller, but too much code is getting repeated. So how can avoid this situation?
I am using Swift 3. I am new to iOS. Any help will be appreciated!
Most duplications are solved by using functions. The first step is to extract that code into a function, the second step is to use the same function from multiple places.
You can add it to an extension, for example:
extension UIViewController {
func addShareButtons() {
...
self.navigationItem.setRightBarButtonItems([youtbBarBtn, twitterBarBtn, fbBarBtn], animated: false)
}
}
and only call
self.addShareButtons()
from every controller that needs the buttons.
You can add button handlers to the extension too.
Another method is to use a UIViewController subclass but that's always a problem if you want to use a UITableViewController subclass.
You can design a custom navigation controller and add these code to the navigation controller. inherit the navigation controller to your storyboard or programmatically where you want to use.
//sample code
class "YourNavigationCorollerName": UINavigationController, UINavigationControllerDelegate {
override func viewDidLoad() {
super.viewDidLoad()
//declare here you code, what you want
}
}
Assuming that these buttons ALWAYS have the same behavior, you can create a custom class for them, and place the repeated code there. For instance:
class FacebookButton : UIButton {
override init() {
super.init()
self.frame = CGRect(x: 0, y: 0, width: 30, height: 30)
self.setImage(UIImage(named: "Facebook.png")!, for: .normal)
}
}
...I think the compiler will yell at you for initializing a UIView without a decoder and frame, but hopefully you get the idea.
To improve on this, you could 1) create a custom UINavigationController with the UIBarButtonItems you want to use, and reuse that controller, and/or 2) create a protocol like the following:
protocol FacebookBtnHandler {
func fbBtnPressed()
}
...and have any relevant VCs conform to it. This would allow you to assign the target and selector for the button in the FacebookButton init method, where you assign the image and frame, and hence prevent repetition of that line, as well.
Try to implement bar button by creating subclass of UIBarButton
class Button: UIBarButtonItem {
convenience init(withImage image : UIImage,Target target: Any, andSelector selector: Any?){
let button = UIButton(type: .custom)
button.setImage(image, for: UIControlState.normal)
button.frame = CGRect(x: 0, y: 0, width: 30, height: 30)
button.addTarget(target, action: selector, for: UIControlEvents.touchUpInside)
self.init(customView: button)
}
}
let fbImage = UIImage(named: "Facebook.png")!
let twitterImage = UIImage(named: "Twitter.png")!
let youtbImage = UIImage(named:"YouTube.png")!
let fbBtn = Button(withImage: fbImage, Target: self, andSelector: #selector(HomeViewController.fbBtnPressed))
let twitterBtn = Button(withImage: fbImage, Target: self, andSelector: #selector(HomeViewController.twitterBtnPressed))
let youtubeBtn = Button(withImage: fbImage, Target: self, andSelector: #selector(HomeViewController.youtubeBtnPressed))
self.navigationItem.setRightBarButtonItems([youtbBarBtn, twitterBarBtn, fbBarBtn], animated: false)
and make it for all your view controller
extension UIViewController {
func addButtons() {
// add above code
}
}

RadioButton in swift

I am new to swift and just embeded a SSRadioButtonsController in Xcode now I want this to be displayed with some text in a UIAlertView.
I have done this but it doesn't work at all.
#IBAction func infoClicked(sender: UIButton) {
self.displayAlert("My Health Action Plan Detail", message: "A Health Action Plan is personal plan describing what you need to do to stay healthy. Using the plan can help you focus your health activities.")
var radioButtonController = SSRadioButtonsController()
radioButtonController.setButtonsArray([button1!,button2!,button3!])
var currentButton = radioButtonController.selectedButton()
}
I need to display some radio buttons with text alongside in alert view
As #matt said You cannot add interface a UIAlertView or UIAlertController. And you can add ssradion button to view like this.
let radioButton = SSRadioButton(frame: CGRect(x: 0, y: 0, width: 100, height: 20 ))
radioButton.circleRadius = 8
radioButton.circleColor = UIColor.redColor()
radioButton.setTitle("1", forState: .Normal)
radioButton.setTitleColor(UIColor.blackColor(), forState: .Normal)
let radioButton1 = SSRadioButton(frame: CGRect(x: 0, y: 0, width: 100, height: 20 ))
radioButton1.circleRadius = 8
radioButton1.circleColor = UIColor.redColor()
radioButton1.setTitle("2", forState: .Normal)
radioButton1.setTitleColor(UIColor.blackColor(), forState: .Normal)
var radioButtonController = SSRadioButtonsController(buttons: radioButton, radioButton1)
radioBtnController.delegate = self
add radiobutton to view
self.view.addSubView(radioButton)
self.view.addSubView(radioButton1)
and if you want to detect which button is clicked you need to implement SSRadioButtonControllerDelegate method didSelectButton.

Make the navigationbar title clickable swift

I would like to make the navigationbar title to be clickable. When user click on it, it should perform a segue. But I have no idea how to do this.
I have tried the following to get the title and apply the Tap gesture to it.
var subviews = self.navigationController?.navigationBar.subviews
if let subviews = subviews {
// Better check for array length before accessing to the 1st element
var subview = subviews [0]
}
but its giving me error Variable subview inferred to have type AvyObject, which may be unexpected
One more approach to add button as a title of navigation controller.
You need to set navigation item title view to your button object
Create button object in viewDidLoad() method:
Swift 4.0 Edit
let button = UIButton(type: .custom)
button.frame = CGRect(x: 0, y: 0, width: 100, height: 40)
button.backgroundColor = .red
button.setTitle("Button", for: .normal)
button.addTarget(self, action: #selector(clickOnButton), for: .touchUpInside)
navigationItem.titleView = button
Here you can see in last line button is directly set to the titleView of navigationItem which will add button at the center of navigation bar.
Action method for button is below:
#objc func clickOnButton() {
}
Kampai's answer updated for Swift 3:
let button = UIButton(type: .custom)
button.frame = CGRect(x: 0, y: 0, width: 100, height: 40)
button.setTitle("Button", for: .normal)
button.addTarget(self, action: #selector(self.clickOnButton), for: .touchUpInside)
self.navigationItem.titleView = button
To get rid of that error, specify a type for your if let constant. I'd also recommend changing that if let constant name since it's the same as the one already declared in the previous line.
var subviews = self.navigationController?.navigationBar.subviews
if let subviewArray:NSArray = subviews {
// Better check for array length before accessing to the 1st element
var subview:UILabel = subviewArray[0] // <-- If the subview's a UILabel
}

Resources