ios - RxCocoa - prevent multiple view controller pushes when there's lag -


as case both reactive , non-reactive ios projects alike, if have ui element (e.g. button or table view cell being selected) pushes view controller onto navigation stack, if there's lag reason (especially on older devices) repetitive taps can result in duplicate pushes , bad ux.

normally disable element after first tap.

for example:

@ibaction func mybuttontap() {      button.isenabled = false     dotherestoftheaction() } 

i relatively new rxswift. trying figure out appropriate reactive way implement fix few bugs in app views pushed repetitively.

some thoughts:

could use debounce or throttle seems bandaid , won't fix every situation.

i'm thinking best way dispose of subscription once expected event has occurred.

let disposable = tableview.rx.itemselected     .subscribe(onnext: { [weak self] indexpath in          self?.performsegue(withidentifier: "mysegueidentifier", sender: self)     })  ...  func prepareforsegue() {     mydisposable.dispose()     finishprepareforsegue() } 

although if want unsubscribe inside subscribe block, compiler complains using variable inside own initial value, makes sense. suppose there workarounds wonder, there better way? maybe reactive operator i'm missing?

tried searching around similar examples results limited.

thanks

edit: perhaps takeuntil operator?

possibly relevant question.

one thing see lot @ company use of rx's variable logininflight variable<boolean>. defaulted false , when command run login flip true. boolean tied login button once user clicks login subsequent clicks not anything. implement wherever user can click on change screens make sure there isn't call / event in progress.

we follow mvvm here's example based on that. tried show barebones down below still makes sense below.

loginviewcontroller

class loginviewcontroller: uiviewcontroller {     @iboutlet weak var signinbutton: uibutton!      override func viewdidload() {         super.viewdidload()          ...          // commandavailable talking above         viewmodel?             .logincommandavailable             .subscribe(onnext: {[unowned self] (available: bool) in                  self.signinbutton.isenabled = available             })             .adddisposableto(disposebag)          signinbutton.rx.tap             .map {                 // send login command                 return viewmodel?.logincommand()             }.subscribe(onnext: { (result: loginresult)                 // if result successful can send user next screen             }).adddisposableto(disposebag)     } } 

loginviewmodel

enum loginresult: error {     case success     case failure }  class loginviewmodel {     private let logininflight = variable<bool>(false)      private var emailaddressproperty = variable<string>("")     var emailaddress: driver<string> {         return emailaddressproperty             .asobservable()             .subscribeon(concurrentdispatchqueuescheduler(queue: dispatchqueue.global()))             .asdriver(onerrorjustreturn: "")     }      ...      var logincommandavailable: observable<bool> {         // let user login if login not happening , user entered email address          return observable.combinelatest(emailaddressproperty.asobservable(), passwordproperty.asobservable(), logininflight.asobservable()) {             (emailaddress: string, password: string, logininflight: bool) in                 return !emailaddress.isempty && !password.isempty && !logininflight         }     }      func logincommand() -> driver<loginresult> {         logininflight.value = true          // make call login         return authenticationservice.login(email: emailaddressproperty.value, password: passwordproperty.value)         .map { result -> loginresult in             logininflight.value = false             return loginresult.success         }     } } 

edit toggling command based on availability

loginviewcontroller

class loginviewcontroller: uiviewcontroller {     @iboutlet weak var signinbutton: uibutton!      override func viewdidload() {         super.viewdidload()          ...          // commandavailable talking above         viewmodel?             .logincommandavailable             .subscribe(onnext: {[unowned self] (available: bool) in                  self.signinbutton.isenabled = available             })             .adddisposableto(disposebag)          signinbutton.rx.tap             .map {                 return viewmodel?.logincommandavailable             }.flatmap { (available: bool) -> observable<loginresult>                 // send login command if available                 if (available) {                     return viewmodel?.logincommand()                 }             }.subscribe(onnext: { (result: loginresult)                 // if result successful can send user next screen             }).adddisposableto(disposebag)     } } 

Comments

Popular posts from this blog

angular - Ionic slides - dynamically add slides before and after -

minify - Minimizing css files -

Add a dynamic header in angular 2 http provider -