I'm new to rx and curious about a question: What's the replacement of override in Rx?
For codes I have read about rx, a button is configured like:
override func viewDidLoad() {
super.viewDidLoad()
updateConversation()
self.naviAvatar.rx.tap
.debug("naviAvatar tap")
.subscribe(onNext: { _ in
print("didTapNaviAvatar")
})
.disposed(by: disposeBag)
}
and it works perfect.
However I meet a question that in a subclass I want to silent the button and I don't know how to achieve in rx.
In my previous code, I have following codes:
class A: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let tapRecognizer = UITapGestureRecognizer(target: self, action: #selector(didTapNaviAvatar(_:)))
self.naviAvatar.addGestureRecognizer(tapRecognizer)
}
#objc func didTapNaviAvatar(_ sender: Any) {
print("didTapNaviAvatar")
}
//...
}
class B: A {
// Silent the method, do nothing.
override func didTapNaviAvatar(_ sender: Any) {}
//...
}
I came up with an idea that I can reconfigure the naviAvatar in B's viewDidLoad method. But what if I have number of codes(like 20 lines, including mapping, filtering, configuring) about the button's behavior but I just want to change only one line(like just override the button title on touch down)?
Any helps would be appreciated.
Weak self isn't needed because there is no delay or async method fired on a tap action. So you can just pass the method and it will trigger the method overridden in class B.
class A: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
naviAvatar.rx.tap
.debug("naviAvatar tap")
.subscribe(onNext: didTapNaviMoreButton)
.disposed(by: disposeBag)
}
#objc func didTapNaviAvatar(_ sender: Any) {
print("didTapNaviAvatar")
}
}
class A: B {
override func didTapNaviAvatar(_ sender: Any) {}
}
Related
EDIT: I have decided to change the way my app works, so this problem is solved. Thanks to everyone who helped!
I have a modal controller where when I press a button it dismisses the view. What I want to do is change a variable in another view controller when I dismiss it, is that possible? Or, if this doesn't work, is there a way for me to access the changed variable of another swift file? I will add my code below:
class PopupViewController: UIViewController {
var event = ""
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
#IBAction func dismiss(_ sender: Any) {
dismiss(animated: true, completion: nil)
}
#IBAction func event910(_ sender: Any) {
event = "storyTime"
dismiss(animated: true, completion: nil)
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
let vc = segue.destination as! ViewController
vc.event = event
}
}
I want to pass the changed variable "event" to another view controller, how can I do this?
Delegate View Controller is as follows. : -
it is the place where you will send the data to the next swift file
protocol myprotocol {
func anyfunction(_ param1:String)
}
struct mystruct1 {
var delegate:myprotocol?
// where you want tot start the delegate / send the data to the next file
func anymethod(){
delegate.anyfunction(sendTheDataYouWant)
}
}
// it is here you will receive the data
class anyclass:UIViewController ,myprotocol {
let class1 = mystruct1()
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
class1.delegate = self
}
func anyfunction(param1:String){
// here Save the data you want
// because this function will be triggered as delegate will be called
}
}
ps:- I reccomend you to read https://docs.swift.org/swift-book/LanguageGuide/Protocols.html
& apple docs
I've just started learning RxSwift. I've added a UIButton with an observable in and a suscribe method that should trigger everytime data changes, but I don't get it to work. What am I missing?
#IBAction func buttonAction(_ sender: Any) {
publishableSubject.onNext("GURKA")
}
override func viewDidLoad() {
super.viewDidLoad()
let bag = DisposeBag()
_ = publishableSubject.subscribe(onNext: {
print($0)
}).disposed(by: bag)
}
Your dispose bag is local so it de-inits when viewDidLoad exits and that will dispose the observable chain you setup. For what you describe, just moving the dispose bag to the class level should fix it.
let publishableSubject = PublishSubject<String>()
let bag = DisposeBag()
#IBAction func buttonAction(_ sender: Any) {
publishableSubject.onNext("GURKA")
}
override func viewDidLoad() {
super.viewDidLoad()
publishableSubject
.subscribe(onNext: {
print($0)
})
.disposed(by: bag)
}
You might want to consider importing the RxCocoa library as well. It sets up the action for you so you can write less code:
override func viewDidLoad() {
super.viewDidLoad()
myButton.rx.tap
.map { "GURKA" }
.subscribe(onNext: {
print($0)
})
.disposed(by: bag)
}
I'm currently writing my first swift app. Currently there is one view/view controller that loads when the app is run as well as a popup window tied to a separate view-controller (like so: https://www.youtube.com/watch?v=S5i8n_bqblE). When I close the pop-up I want to update several things on my original view and run some code. However, neither func viewDidLoad() nor func viewDidAppear() seems to run. And I can't do anything from the pop-up view since I don't have access to the components in the main view-controller from it. What should I do?
The pop-up is "presented modally" if that makes a difference?
I'm assuming you have a MainViewController from which you're presenting the PopupVC. You can use delegate pattern here.
Define a PopupVCDelegate as follow
protocol PopupVCDelegate {
func popupDidDisappear()
}
In your PopupVC define a delegate property of type PopupVCDelegate. And in the closePopup method, call the delegate method popupDidDisappear
class PopupVC: UIViewController {
public var delegate: PopupVCDelegate?
override func viewDidLoad() {
super.viewDidLoad()
}
#IBAction func closePopup(_ sender: Any) {
dismiss(animated: true, completion: nil)
delegate?.popupDidDisappear()
}
}
Now any class that adopts this delegate will be able to receive the callback when the closePopup is called. So make your MainViewController to adopt this delegate.
class MainViewController: UIViewController, PopupVCDelegate {
override func viewDidLoad() {
super.viewDidLoad()
}
func showPopup() {
let popupViewController = //Instantiate your popup view controller
popupViewController.delegate = self
//present your popup
}
func popupDidDisappear() {
//This method will be called when the popup is closed
}
}
Another way is to fire a notification through NSNotificationCenter on closePopup and add an observer in MainViewController to listen to that notification. But it is not recommended in this scenario.
Edit
As you have asked for the NSNotificationCenter method. Please change your classes as follow
class PopupVC: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
}
#IBAction func closePopup(_ sender: Any) {
dismiss(animated: true, completion: nil)
NotificationCenter.default.post(name: NSNotification.Name("notificationClosedPopup"), object: nil)
}
}
class MainViewController: UIViewController, PopupVCDelegate {
override func viewDidLoad() {
super.viewDidLoad()
NotificationCenter.default.addObserver(self, selector: #selector(onPopupClosed), name: NSNotification.Name(rawValue: "notificationClosedPopup"), object: nil)
}
#objc func onPopupClosed() {
//This method will be called when the popup is closed
}
deinit {
NotificationCenter.default.removeObserver(self, name: NSNotification.Name(rawValue: "notificationClosedPopup"), object: nil)
}
}
I'm absolute newbie in Swift and OSX development, and I'm sorry if my question will be too noob. I want to understand principles of navigation between NSViewControllers.
I have my default ViewController, where are login and password fields and button to login. After click on button, returns token. And now I trying to change "view" to SecondViewController and save somewhere token, I will need it in future. How can I do it? and it possible to do this in function?:
#IBAction func loginButton(_ sender: Any) {
....
}
Thank you!
You need to use segues to perform this action.
First make the segues connections between the ViewControllers using to storyboard editor. After that you need to give the segues an identifier on the storyboard's attributes inspector. Then in your code you can call the new ViewController by the segue like the code below.
With this code you can pass the data using the button:
class ViewController: NSViewController {
var dataToPass: String = "DataToPass"
override func viewDidLoad() {
super.viewDidLoad()
}
#IBAction func loginButton(_ sender: Any) {
performSegue(withIdentifier: NSStoryboardSegue.Identifier(rawValue: "segueIdentifier"), sender: self)
}
override func prepare(for segue: NSStoryboardSegue, sender: Any?) {
if segue.identifier!.rawValue == "segueIdentifier" {
let destinationViewController = segue.destinationController as! ViewController2
destinationViewController.dataToReceive = dataToPass
}
}
}
class ViewController2: NSViewController {
var dataToReceive: String
override func viewDidLoad() {
super.viewDidLoad()
}
}
And with this code you will use the override viewWillAppear
class ViewController: NSViewController {
var dataToPass: String = "DataToPass"
override func viewDidLoad() {
super.viewDidLoad()
}
override func viewWillAppear() {
performSegue(withIdentifier: NSStoryboardSegue.Identifier(rawValue: "segueIdentifier"), sender: self)
}
override func prepare(for segue: NSStoryboardSegue, sender: Any?) {
if segue.identifier!.rawValue == "segueIdentifier" {
let destinationViewController = segue.destinationController as! ViewController2
destinationViewController.dataToReceive = dataToPass
}
}
}
class ViewController2: NSViewController {
var dataToReceive: String
override func viewDidLoad() {
super.viewDidLoad()
}
}
In both cases you need to assure the data you want to pass to the other view controller is not null.
here is my protocol definition.
protocol ActivityIndicatorDelegate: class {
func showIndicator()
func hideIndicator()
func barcodeError()
func categoryError()
func descError()
func reasonError()
func costError()
}
Then in my Custom cell class I create weak reference and I call delegate function
class ProductTableViewCell: UITableViewCell {
weak var indicatorDelegate: ActivityIndicatorDelegate?
#IBAction func stockUpdate(_ sender: Any) {
indicatorDelegate?.categoryError()
}
}
Then in my UITableViewController class
class ProductTableViewController:
UITableViewController,ActivityIndicatorDelegate{
override func viewDidLoad() {
super.viewDidLoad()
let cellDelegate = ProductTableViewCell()
cellDelegate.indicatorDelegate = self
}
func categoryError() {
//self.showAlert(alertTitle: "Error!", alertMessage: "Category Should not be empty")
print("Error")
}
}
I have written all these in a single file. What I'm doing wrong here? Can some one help me to solve this. Thanks in advance.
You should not set the delegate in viewDidLoad. This will only set the delegate of the cell that you just created, instead of all the cells in the table view.
You should do this in celForRowAtIndexPath:
let cell = tableView.dequeue...
// configure the cell...
cell.indicatorDelegate = self