Coding an iOS app is hard work, so it makes sense that devs want to cut corners and find ways to get their app online as quickly as possible. But a successful app will be around for a long time—that means years of bug fixing, feature enhancements, and working with other coders.
In this article, I’ll share three things to steer clear of during iOS development that will make your apps easier to build and easier to maintain.
1. Don’t Be Afraid of Constants
While it seems that variables are more versatile than constants, it still isn’t a good idea to default to variables when you can use a constant instead. So what’s so great about constants? A number of things, actually!
Readability
One of the best things about constants is their readability. Let’s look at an example: you are writing an e-commerce type app. You may want to add a local sales tax rate of 8.75%, but other developers wouldn’t know what that number means. Let’s look at an example:
A developer named Steven comes aboard your team, and he is a coding ninja, but he lives in a country overseas. In this country, there is no such thing as sales tax (lucky Steven), and therefore, he doesn’t know anything about it.
If you were to use a variable for your sales tax rate, he could change it in just one line of code, and the results of that could seriously harm your app. Just changing the keyword from var
to let
would have the compiler telling him that the value cannot be changed, and he would realize that you intended it to be immutable.
Value Reference
Another way that let
is useful is to refer to a value in your code. If you are making an app, you may want a certain color scheme. Instead of copy-pasting your colors wherever they are needed, you can use a constant to refer to that specific color.
This way, if you were to change the color, you would just need to change it in one place instead of finding every single reference to the color and changing it multiple times.
Class or Struct Instantiation
When you create a singleton, you also need to create a shared instance of the class. You would usually do this by declaring a static let
inside of the class declaration. After that, you would name the constant and assign it to an instance of the class and use it throughout your app.
Adding to that, if you needed to instantiate (create an instance of) a regular class, perhaps in ViewController.swift, you would create a constant and assign it to an instance of your desired class, leaving you with a reference that you can easily take advantage of throughout the file. This is another great use of constants.
As you can see, there are many reasons that constants are great. They increase code readability, they are useful for storing immutable values, and clearly, they are not as useless as you think. Do yourself a favor by getting in the habit of using constants whenever possible, and only changing them into variables if you absolutely need to mutate their values—it will make you a better programmer.
2. Don’t Force Unwrap Optionals
Optionals are a very powerful feature of Swift. They are just types like int
and String
, annotated by a question mark after the type declaration. If you want to declare a variable as an optional string, you would just write:
var someVariable: String?
This tells the compiler that there either can be a value or there might be no value at all. String?
and String
are considered to be two different types.
Think of optionals as a gift box. As I mentioned, this gift box may or may not have a value, and if you want to find out, you must unwrap the optional first. There are many ways of doing this:
The Wrong Way
Forced Unwrapping
This operation (performed by using an exclamation mark) is called the Bang Operator. Don’t use it! Force unwrapping your variables is never a good idea. If the value of the optional you are trying to unwrap is nil (nothing), your app will crash, and who wants that? Anyway, let’s look at the following block of code:
var someVariable: String? var somethingElse: String = "hello" func setupApp() { self.somethingElse = self.someVariable! }
In this example, the app would crash because we never defined a value for someVariable
, and we are trying to assign it to a variable of type String
. This defeats the whole purpose of optionals, which are there to help protect us from errors like this!
Let’s look at some of the correct ways of handling this same situation.
The Right Way
Optional Binding
This is one of the most popular methods of dealing with optionals. In this method, you simply assign an optional value to a constant using an if
statement. If the optional can be unwrapped, the compiler enters the closure, and you can use the constant that was created. Otherwise, you fall into an else
statement and pretend that nothing happened. Let’s look at an example of this:
var someVariable: String? var somethingElse: String = "hello" func setupApp() { if let theThing = someVariable { self.somethingElse = self.someVariable! } else { print("error") } }
Using the same example as last time, but with optional binding instead, we can see that instead of crashing, the compiler enters the else statement and prints “error.”
Optional Chaining
Another common way to safely unwrap optionals is optional chaining. This is a great way to avoid nil values cleanly, and in one line of code. When you use this method and come across a nil value, that line of code simply ceases to execute. Here’s an example of this:
var someClass: SomeClass? = SomeClass() var somethingElse: String? func setupApp() { self.somethingElse = someClass?.createString() }
Basically, if someClass
is nil, the entire line will not execute, and the value of somethingElse
will become nil. If there is a value, like the example above, it will be assigned to the variable somethingElse
. In either case, the app will not crash.
Nil Coalescing
This method handles optionals with a single line, but unlike the method above, you need to provide a default or “else” case (in case the optional turns out to be nil). Let’s look at an example:
var someVariable: String? var somethingElse: String = "hello" func setupApp() { self.somethingElse = someVariable ?? "error" }
Although this may seem a little cryptic, it simply means that if the left-hand statement has a value (in other words is not nil), it will be used. If it is nil, then the default statement will be used—in this case, a hard-coded string. It is worth noting that the right-hand statement needs to be of a non-nil and non-optional type (otherwise, the purpose of this would be defeated).
3. Don’t Ignore Architecture
Another common mistake is failing to structure your code in a way that it is sustainable, maintainable, and efficient. Many people cram all of their code into their ViewController
classes, and this can make your code hard to change and debug.
As cliché as this may sound, this really is the foundation of how you program your app. Let’s say you are building a house, your dream home. This house is five stories high, so if you don’t build a strong foundation and follow the blueprints, it will probably just topple over.
The foundation of an iOS app is the design pattern that you choose. Let’s look at two of the most commonly used patterns.
MVC (Model-View-Controller)
The Model-View-Controller or MVC design pattern separates each part of your code into three parts: the model, the view, and the controller.
- Model: The model is essentially the data of the app. This handles things like reusable structures and classes that deal only with the data of the app. The model does not handle anything relating to the view or how the information will be shown to the user.
- View: The view is responsible for only the visual representation of the data, and it also handles user interaction. It does not handle anything regarding data, nor does it deal with specific views. It is simply a reusable class which can be used multiple times without repeating code.
- Controller: The controller is the boss. It brings data from the model, and then sends it to the view to finally display it to the user. This is typically in ViewController.swift, and it listens to input and changes the model as needed.
There are many variations of this, such as MVVM and MVP. It’s worth reading up on them, but the principle is similar to MVC, so we won’t be covering them here. These are all called design patterns, and they make our code modular.
Let’s look at another design pattern which can complement the app pattern you choose to use.
Singletons
A singleton is a single instance of a class that is present at all times in memory. So why do we care about this? Well, let’s say that you are building an app that connects to a database. You need a place to put all of your data service connections. This would be a perfect place to use singletons. Look at the code below; it will show you how to construct a singleton:
// Declaration class DataService { static var shared = DataService() func createUser() { } } // Call-site DataService.shared.createUser()
If you follow these simple tips, your app will be easier to maintain, and bugs will be more obvious to find before your customers do.
Conclusion
In this article, we saw three mistakes that iOS app developers make that might seem to make coding easier, but actually cost a lot more work in the long term.
Remember, building an app is only part of the challenge—you also need to fix bugs, add features, and share the code with other developers. Following best practices like using constants, handling optionals correctly, and using architectural patterns will make your app easier to build and easier to maintain.
While you’re here, check out some of our other posts on iOS app development!
-
SwiftWhat’s New in Swift 4
-
Android SDKGoogle I/O 2017 Aftermath: What’s New in Android Studio 3?
-
iOS SDKFaster Logins With Password AutoFill in iOS 11