Idea for this article came from a you tube video named “try! Swift Tokyo 2018 — Optimizing Swift code for separation of concerns and simplicity”.
So for starters lets consider the following requirement for an iOS application
1. Make an API call
2. If API call returns some data then update / populate the user interface.
3. If API fails then let the user know the reason for the failure and give them a retry option.
Most common approach to go about this problem is to create a bunch of optional UI elements and assign them value as and when needed like following
Issue with this approach is that we have declared too many optionals here and because of that we have to write extra code for handling all these optionals.
Now take a look at the following code
Here we are making an API call and in the callback closure of the API call, we have written the logic to update the UI as per the response i.e. success / failure.
So what’s the problem here?
Suppose in future if a new requirement comes where a new view needs to be added to the existing view hierarchy or an existing view needs to be modified then people might write their own separate methods to implement the same and which will make view updating logic scattered all over the place which will lead to hard to debug code base.
Also making any further changes without breaking the existing application logic becomes a challenging task.
Solution — Swift Enums.
Here we have created an enum with all the possible UI states as enum cases. We have aslo created property name “state” to track the current application state and accordingly update the UI state of the application.
See the following code for details.
Here this “state” property abstracts all the UI update logic which has following advantages
1. At the start of the article we have discussed the issue of declaring too many optionals. So now due to enums we can get rid of all those optional UI elements and create and pass those UI elements as enum parameters when required.
2.This adds readability to the code as it makes UI changes corresponding to every application state very clear.
3. Extending this code base for any future requirements is easy as you just have to add the State case / cases (if required) and update the state property accordingly.
One important piece of code mentioned in the codesnippet above is “visibleView = someView”. Lets see what and how of it
Here “visibleView” is just a property in which we are removing the existing visibleView in the “willSet” call and adding the new value of “visibleView” as a subview of the view controller’ view in the “didSet” call.
But how all the views in this class responds to these two methods i.e. addAsSubView(inView:) and removeAsSubViewFromParentView(). Answer to this question is a protocol.
So this is the protocol that all the views in this example confirms to which makes the logic to add and remove views very simple and also due to this, logic to add and remove views is abstracted inside those views, making our main view controller less cluttered.
Lets see how the API call looks after the introduction of this enum
Here we are updating the state property as per the api response and the state property takes care of all the UI update logic.
I have made two projects one is the starter project and other one is the completed project. Starter project is for those who are more of a DIY kind and completed project are for those who just want to see and execute the final changes.
Note — Starter project is added a zip file in the following repository.
That’s it for now and i hope you find this helpful. Thanks for reading. 😀😀😀
Resource for this article:
Git repo link — https://github.com/DVdroid/StateBasedUI.
Some post credit stuff — #MCU_Fan
The approach explained here is just a guideline and not a rule that you must have to follow. Like consider a scenario where you have an API call which populates a tableview. So now if a requirement comes where you have to sort the values of the tableview then this approach may cause an issue as you only have local reference of the tableview which will not be available outside the “state” property.
So solution of this problem is to create a reference of the tableview that can be access at the class level.
FYI — I discussed this issue with @javi (speaker of the talk mentioned above) and he suggest this solution.