Swift code improvements that I used in my latest iOS app.
In one of my previous articles I jokingly said that every iOS developer should write their very own To-Do list app. One of my friends read the article and messaged me: “You don’t have To-Do list app yourself so are not an iOS developer”. So I decided to build one and use all sorts of improvements that I wanted to try. Without further ado here are some code tips:
1. Reuse Code Effectively.
As Albert Einstein said, “Insanity is doing the same thing over and over again and expecting different results.” Applying this to software development we may say: “Do not write the same code twice”. Modules allow you to effectively reuse parts of your code, gradually increase the quality of your codebase, try different approaches without hurting the whole project and they are suitable for testing.
It does not really matter how you will implement the modular approach in your app: through your private CocoaPods, Carthage or by creating Frameworks. The main reason here is not to repeat yourself but rather improve and find better ways to do certain things.
For example, I’ve made an extension on UIApplication that stores current app version. This code goes to my Utility framework. This way I can easily track updates and react accordingly like ask for feedback on new features. Good thing is that I don’t have to write this code ever again. When I need this code in my next app all I have to do is just include Utility framework and use it right away. That’s how I can focus on many different important things like Analytics and respond to user feedback, search for new features and improve my code quality.
2. Avoid Unessecary Inheritance.
If you ask a newbie software engineer about inheritance — he or she will be a huge advocate of it. But an experienced developer will be very cautious about this topic. So instead of spawning several subclasses of let’s say UITextField or ⌘C ⌘V similar code snippets for styling its UI I’ve made this:
Now we have exactly one place where UITextField is configured, no class hierarchies, and one-line configuration of the element. Read more about styles here.
3. Use Protocols Smart.
I’ve made a small sticker above my desk with a simple motto:
“Use protocols more not more protocols”
The problem is simple: I want more statistics inside of my app in order to test features, collect feedback and make intelligent product related decisions. For now, I’m only using Mixpanel and Amplitude but planning to add more of them in the future or remove useless ones. With a simple protocol, I can wrap up all related logic and no longer be dependent on analytics SDK syntax.
and here is an example of MixpanelProvider
Initialization is simple:
Analytics.shared.setup(withAnalyticsProviders: [.mixpanel : “abcdefghijklmnopqrstuvwxyz”,
.amplitude : “abcdefghijklmnopqrstuvwxyz”])
And you can track the event once in your code
and it will be tracked in all providers.
4. Do not break S in SOLID.
If you are planning to create a new class and its name contains word Manager stop and think for a second. Often SomethingManager class is used to wrap logic that includes several tasks: it makes network call, gets a response, parses it and returns it. This is a direct violation of Single Responsibility principle. But don’t worry. Even the wisest of iOS developers have made similar mistakes in the past or still making them. What can be done is a simple distribution of responsibilities.
A lot of things can be done here. First, you need to define your network layer code in a way that it will make network calls in one object, parsing the response and building modelObjects from it in another. Check my article about services. By doing this you eliminate the need in SomethingManager classes.
5. Avoid Fat Methods.
The settings screen is a very common part of an iOS application. It often looks like this:
So basically it is a grouped UITableView with a bunch of different cells: the one with a switch, another with a subtitle, the cell that looks like a button, etc. The simple solution is a huge switch operator. Maybe you can split some of its logic between cellForRowAtIndexPath and willDisplayCellAtIndexPath but it does not really solve anything.
A better solution (not the greatest, anyway) comes with usage of ViewModels. It is an old technique but quite effective.
Now we can spawn a bunch of viewModels, UITableViewCells subclasses with similar structures and add them to the view without touching UITableViewDataSource code. You may want to add reuseIdentifier as a computed property and implement it inside your specific viewModel structs.
I have a huge problem with this solution though. By looking at cellForRowAtIndexPath you can’t tell which cells this tableView uses. So you have to look at Storyboard or write a commentary.
There are plenty of more or less useful tricks that I’ve tried in my project. But I’ve made it in a couple of weeks from prototype to a live app on AppStore.
I’m planning to open my source code in observable future so stay tuned. If you enjoyed this article, please, take a second to recommend and share it. Thank you!