Comments (8)
Hi @yudinm
In order to help you efficiently, It would be great if I could see a bigger part of your code base ... but I assume it is not open source :-( so I will try to give you some insights:
Why VC lifecycle matters ?
The only reason RxFlow "listens" to your ViewControllers lifecycle is to be able to restrain the effects of a Stepper to the VC (and the Flow) that is currently displayed. To do so, RxFlow needs to know if the VC associated to the Stepper that has triggered a new Step is displayed or not, and if yes -> the Step can be given to the Flow, if not -> the Step is ignored.
RxFlow does this to avoid performing a navigation coming from a VC that is not displayed (for instance from a VC that is lower than the current VC in your navigation stack), because that could lead to UIKit errors (by making a VC present a another VC whereas it is not actually the currently displayed VC).
RxFlow also performs such checks at a Flow level.
Handling user connection state
I personally had to deal with "user authentication state" in previous applications. In that case, I like to have a "UserState" value exposed through a Rx Observable by a low level layer (perhaps a UserService or something). This UserState can be an enum representing the current user, for instance:
enum UserState {
case unauthenticated
case authenticated (User)
}
If for some reason, a request returns a code 401, you could mutate the UserState to ".unauthenticated". As it is an Observable, you could react to this mutation.
For instance, the Stepper associated with the root Flow could subscribe to this UserState Observable and and trigger a MyStep.auth step if the state equals .unauthenticated. In that case the root Flow could display a login popup to authenticate the user. Doing so, your app is able to prompt the user to login each time the token is expired.
Could this match your requirements ?
from rxflow.
Hi @yudinm
I Have a few questions:
- In the TaskViewModel, the network call is done in the init function ?
- Is there an error message or it is just not working ?
My take on this -> the MySteps.auth step is triggered too soon (because the network call is done in the init function of the TaskViewModel) and is catched by your Flow whereas the animation is not finished yet. Then your Flow triggers a new navigateXXX function (because of the MySteps.auth step) and then UIKit cannot display the auth screen because of the animation is not finished on the previous screen.
You should try to put your network call in a dedicated function in your viewModel and call this function in the viewDidLoad of the taskViewController.
Keep me in touch.
from rxflow.
Thank you for quick answer.
In the TaskViewModel, the network call is done in the init function ?
No. Network call done in viewDidLoad.
Is there an error message or it is just not working ?
No error. Just did not go to coordinator.rx.willNavigate/didNavigate and so on. Also i try to subscribe on .step in network error handler and see that:
// animated: true
401 Unauthorized!
step: NoneStep()
step: auth
// animated: false
step: NoneStep()
did navigate to flow=TaskFlow and step=auth
did navigate to flow=DashboardFlow and step=auth
did navigate to flow=AppFlow and step=auth
will navigate to flow=LoginFlow and step=login
did navigate to flow=LoginFlow and step=login
step: auth
Checked calls in VC. Found, that network call triggered by let viewWillAppear = rx.sentMessage(#selector(UIViewController.viewWillAppear(_:))).mapToVoid().asDriverOnErrorJustComplete()
. Fixed by replacing viewWillAppear
to viewDidAppear
.
However, problem confuse me. Why Stepper or Coordinator work depends from animation and VC state? In my case we have access token that sends in http headers.
- User get tasks list (first network call)
- Access token invalidates on server
- User taps on task item. Its pushes details VC (second network call)
- Getting network error with status code 401
On this error we want navigate user back to login flow. That kind of error can perhaps in very different cases: on background requests, when user quickly taps on different items and switch screens. How we can assured redirect user to login (or something other) flow without any knowledge about current view state, transitions?
from rxflow.
@yudinm how is it going with yours flows ?
from rxflow.
Hi. Sorry, appeared tasks not related to the Flows.
With VC lifecycle – it's clear.
With connection state we'll use your way, probably. Thank you.
For now we just added extension to ObservableType:
import RxSwift
protocol ErrorHandler {
func handle(_ error: Error)
}
extension ObservableType {
func handleError(_ errorHandler: ErrorHandler) -> Observable<E> {
return Observable.create({ observer in
let subscription = self.subscribe { e in
switch e {
case .next(let value):
observer.on(.next(value))
case .error(let error):
errorHandler.handle(error)
observer.on(.error(error))
case .completed:
observer.on(.completed)
}
}
return subscription
})
}
}
And in ViewModels implement protocol:
extension TaskListViewModel : ErrorHandler {
func handle(_ error: Error) {
guard let error = error as? MoyaError else { return }
guard case .statusCode(let response) = error else { return }
if response.statusCode == 401 {
print("\(response.statusCode) Unauthorized!")
self.services.preferencesService.invalidateUser()
self.step.accept(Steps.auth)
} else {
print("Error statusCode: \(response.statusCode)")
}
}
}
Anyway error handling is a future task in current app.
I would like to add, that ViewControllers as a Stepper mixed with ViewModels as a Stepper produces some confusion. In our case we have agreed to use only ViewModels as a Steppers.
Thank you. Good stuff.
from rxflow.
Thanks for your feedback. You're totally right about ViewModels being the best candidate for Stepper.
If i may make a suggestion, it feels like your extension to ObservableType is doing something very similar to the built-in do(onError) function. Is there a reason you don't use it ?
from rxflow.
Can I close this issue ?
Thanks.
from rxflow.
Yes. Thanks! You may close.
We like to make extension, because we do not want include "big" block in chain. We will call .handleError(self)
in chain. And implement enum of error handlers somewhere outside of ViewModel.
let tasks = input.trigger.flatMapLatest { _ -> Driver<[TaskListViewModelItem]> in
return apiClient.getTasks()
.asObservable()
.handleError(self)
.map{ return $0.map(TaskListViewModelItem.init) }
.asObservable()
.trackActivity(activityIndicator)
.asDriver(onErrorJustReturn: [])
}
from rxflow.
Related Issues (20)
- Child view controller steps HOT 5
- Please document memory management HOT 4
- CompositeStepper not calling InnerSteppers readyToEmitSteps HOT 4
- Block links are invalid HOT 1
- Something strange happening in ios14 HOT 3
- unknown dependency 'RxCocoa' in target 'RxFlow' HOT 6
- `Reactive+UIViewController`'s `dismissed` event is retaining the view controller HOT 2
- Question regarding intended behavior of FlowCoordinator's navigate(to:) function HOT 4
- Flow.rxVisible never emits `true` event when pushing view controller without animations HOT 3
- Coordinator navigate(to: ) does not override initialStep HOT 10
- How to handle opening multiple flows upon clicking a deeplink HOT 3
- Adapt step in the background causes `navigate` to be called on the same thread HOT 6
- Reentrancy anomaly on .forwardToCurrentFlow HOT 9
- Cannot step in child flow after using .multiple with .forwardToCurrentFlow, and others. HOT 1
- How to handle searchResultsController
- Child controllers are never deallocated HOT 5
- Adapt method is disposed before being completed HOT 1
- displayed is incorrect if subscription occurs when view is already on screen HOT 1
- Seeking a new maintainer HOT 8
- Initiating a step from a completion inside of a sink for Future Published (Combine) HOT 5
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from rxflow.