Getting started with Swift
You are new to iOS. You want to dip your toe into the exciting world that is iOS development. However, when you take a peek, you meet the the big bad wolf that is Objective-C. Worry not, Swift is here to save the day. When I first got into iOS, I was a newbie with just three months programming experience which was in Python. I was terrified of what it meant for me to make the shift so soon. However, once I got into Swift, I fell in love. I found it just as easy to read while still having the Pizzazz that makes a language exciting to use. Objective-C on the other hand proved to have a bit of a learning curve because of the way it is generally structured. Let’s compare a sample Objective-C class and a Swift class.
Objective-C
Writing classes in Objective-C can be a bit daunting. This is because Objective-C requires an implementation file and a header file for each class.
A header(.h) file
#import <Foundation/Foundation.h>@class ThisTest;@interface ThisTest : NSObject@property (nonatomic) NSString *objectiveCString;- (void) someMethod;@end
An implementation (.m) file
#import "ThisTest.h"@implementation ThisTestNSString *objectiveCString = @"some string";- (void) someMethod {NSLog(@"This is how you print out");}@end
When I first started out, I found this to be quite intimidating. It also proved to be hectic, as I ended up obsessing about coordinating the naming of variables and methods, figuring what goes where and the whole business of importing.
Swift
With Swift, I realised I could throw everything into one file and concentrate more on logic. All I needed to do was, figure a way to create classes that grouped functionality together.
class ThisTest { var swiftString: String = "This is a Swift string" func someMethod() { print("This is how you print out") }
}
Are you sold? No? Well, Swift is generally more automated. You do not have to concern yourself with what goes on under the hood, memory management is taken care off already. This is not to pit one language against another. Objective-c is a great language, I just would not recommend that anyone who is looking to dip a toe into iOS start off with it.
Starting out with Swift
It took me approximately a month to get completely comfortable with the Swift syntax. We will discuss some of the things I discovered I needed to get to a place where I could comfortably contribute to projects. I recommend you start out with a playground. A playground is basically where you can test out anything. It is easy to use, you do not have to concern yourself with print statements to see whether your code is working. Simply open Xcode, press cmd+N , select playground and get your hands dirty.
Variables and Constants
In swift as in other languages, variables have to be declared before they are used. Variables are mutable and are declared with the keyword var
while constants are immutable and are declared with the keyword let
.
let someType: String = “I am explicitly declared”
var secretType = “You can infer what type I am”
The first one is a constant that has been explicitly declared as a string, the second example is a variable whose type has not been declared. The type is however inferred and the variable is known to contain a string. Some common types you will come across in Swift are String, Bool, Int, Float
.
One of the most exciting things about Swift is optionals. Optionals are used where a variable may not contain a value.
var integer: Int = 9var optionalInt: Int?
The first variable is an integer, it can never be nil. However, with the optionalInt
the value can be nil. When it is first declared as an optional, it is nil by default.
Unwrapping Optionals
Optional variables have to be unwrapped before they are used. If you tried to perform an operation between Integer
and optionalInt
you would get an error that optionalInt
is not unwrapped.
var optionalInt1: Int? = 10var optionalInt2: Int? = 4var sum = optionalInt1 + optionalInt2 //Buildtime error: Value of optional type not unwrapped
There are two ways to unwrap optionals; optional binding and forced unwrapping.
Forced Unwrapping
var optionalInt1: Int? = 10var optionalInt2: Int? = 4var sum = optionalInt1! + optionalInt2!
The above example works, it is however not recommended. This is because whenever the optional is nil, the app crashes. Nobody likes a buggy app! Therefore, unless you are absolutely sure the value will never be nil, never
use forced unwrapping
. There is a better and prettier way to solve the unwrapping problem. Meet our friend, optional binding!
func add() -> Int? { let optionalInt: Int? = 10 let someInt: Int = 8 guard let unwrappedInt = optionalInt else { //optional binding using guard statement return nil
}
return (unwrappedInt + someInt)
}
Collection Types
Collection types in swift are a way to group related items together. In swift, the values in the types are strongly typed. This means the compiler is aware of the types and you can therefore for example, not insert a string into an array of integers.
- Arrays
These store items in an ordered list.
Creating, accessing and manipulating an array
var list1 = ["cookies", "cakes", "muffins"] //explicitly declare contentsvar list2 = [String]() //initializervar list3: [String] = [] //type annotationlist1.count //returns 3, the number of items in the listlist1.append("cupcakes") //this adds the objectlist1[0] //access the object on index(0); the first itemlist1[1] = "1" //attempts to replace item on subscripted index, this raises an error as it is a different type from the one expectedfor item in list1 {
print("\(item) are yummy")
} //prints each of the items and adds the "are yummy" at the end
There are numerous operations that can be performed on arrays. The swift documentation does a great job at explaining these.
- Sets
A set is very similar to an array except that it stores distinct items in an unordered manner. Modifying and accessing a set is very similar to the same in an array.
var planets = Set<String>(),var coolPlanets: Set<String> = ["Earth", "Pluto", "Saturn"]var sadPlanets: Set = ["Uranus", "Pluto"]
- Dictionaries
A dictionary is used to create key, value pairs.
Creating, accessing and manipulating a dictionary
var dictionary: [Int: String] = [:] // type annotationvar dictionary2 = [Int: Int]() // initializervar swahiliDict = ["shoes": "viatu", "tea": "chai"]swahiliDict["shoes"] //print the value associated with subscripted key
swahiliDict.count //print the number of key, value pairsswahiliDict["shoes"] = "njumu" //replace the value at given keyswahiliDict["shoes"] = nil //remove the key as it no longer has a value associated with itfor (key, value) in swahiliDict {print("\(key) in Swahili is \(value)")}//will print "tea in Swahili is chai"
Control Flow
In swift, various statements are used to achieve control flow. These are statements that make decisions based on some conditions. Control flow statements include; those that perform tasks multiple times, those that iterate and those that perform certain tasks based on some conditions.
- while and repeat-while
var counter = 0while counter < 5 { print("Counter is at \(counter)") counter += 1
}
//this loop executes until the given condition is false. In this case, it executes while counter is <5
- if and if-else, guard, switch
if-else: It executes a certain block only if the condition is true. In Swift, the condition to be evaluated has to be either true
or false
unlike in Objective-C.
var time = 1if time > 4 { //this returns true or false print("I am starving!")} else { print("i could eat!") //this block is executed
}
Guard: it is used to transfer control. The conditions should evaluate to true or false.
func printEvenPostiveNumber(_ num: Int) { guard num > 0 else { print(“\(num) is not > 0”) return
} guard num % 2 == 0 else { print(“\(num) is not even”) return
}
}printEvenPostiveNumber(-1) // “-1 is not > 0\n”printEvenPostiveNumber(3) // “3 is not even\n”
Switch: this compares a value with several matching patterns then executes a block based on which it matches first.
let temperature: Int = 20switch temperature {case 1..<15: print("It's sweater weather")case 15..<30: print("Less Monday more summer")default: print("We don't recognise what is happening here")}
for-in: these are used to loop over collection types or a range of numbers
for values in 1...5 { print (values)} //this prints all the values between 1 and 5
Functions
Functions are chunks of code that perform a task.
In the spirit of writing self-documenting code. It is important to give a function a name according to what it does. One of the things I came to appreciate when I was getting into Objective-C is developers who give functions accurate names, these men and women are the heroes who don’t wear capes.
func basic() {}
basic()
//this function has no argumentsfunc withParameter(parameter: Int) {}
withParameter(parameter: 3)
//has an argument that matches the parameter namefunc withReturn() -> Int { return 2 }
withReturn()
//returns a value 2, you can ignore it, if you do not write a //return, it raises an error as the function expects a returnfunc withMultipleParameter(parameter1: Int, parameter2: Int) {}
withMultipleParameter(parameter1: 3, parameter2: 5)func returnsTuple() -> (Int, Int) { return (2,3) }
returnsTuple()
//return (2,3)func drawLine(from point1: Int, to point2: Int) {}
drawLine(from: 3, to: 6)func optionalParameterName(_ optionalParameterName: Int, justParameter: Int) {}
optionalParameterName(3, justParameter: 5)
//a _ before the parameter label tells the compiler that we do not //want to write the argument label when calling the function
There is special type of functions known as closures. Closures are fun, closures will make you a bad ass. I recommend swift documentation on this.
Structs and Classes
If you have some previous experience with programming, you have definitely come across classes. Classes are ideally the same across the board. However, in swift there is this sweet little thing we call structures. Structures are ideally similar to classes save for a neat little difference. Classes are reference types while structures are value types. One of the things I suffered through when I was trying to navigate swift was the difference between these two, where to use them and the advantage of one over the other. This post made things so much easier. Here is an example that will hopefully clear out the differences.
- Reference Types
An object in a class is a reference type.
class ClassObject { var a = "Hey" }var object1 = ClassObject()var object2 = object1
//creates a shared instance, both variables refer to the same //instanceobject1.a = "There!"print(object1.a, object2.a) //prints "There There"
- Value Types
An object in a structure on the other hand is a value type.
struct StructObject { var a = "Hey" }var object1 = StructObject()var object2 = object1
//creates two independent instances, each with a copy of it's own //dataobject2.a = "There!"print(object1.a, object2.a) //prints "hey there"
Other than this difference, structures and classes are essentially the same.
class Example { //give the class a meaningful name var subject: String = "Structures" //class property func giveDefinition() { //class method print("This is the definition for \(subject)")
}
}var example = Example() //instantiating a classexample.giveDefinition() //calling the class method
Classes and structures have variables or constants that are referred to as properties and functions that are referred to as method. If you do not give an initial value for properties in the classes, you will get an error.
class Example { var subject: String
init() { subject = "swift" } func giveDefinition() { print("This is the definition for \(subject)")
}
}var example = Example()example.giveDefinition()
Extensions
Sometimes you have classes that have some functionality in only special cases. Say you have a class that draws a chart. This class may be used in several places in your app. However, you may need it to have special divisions in some cases. It does not make sense to add such functionality globally yet it will be applicable in limited places. Enter extensions; these add computed properties, methods, initializers or protocols. We have not spoken about protocols I know. Worry not, protocols is another super power that swift possesses that we will look at shortly.
class BareMinimum {}extension BareMinimum { //add functionality to the above class}
Extensions are very exciting to study and work with. You could take a deep dive and discover all the cool things you can do with extensions.
Enumerations
These group related values so that you are able to work with them in a type safe way.
enum Color { case blue, green, yellow, red, black}
var colorToWear = Color.blue
colorToWear = .red
//after first assigning it, you can use dot syntax to access other //values
Matching enumerations with a switch statement
enum Color { case blue, green, yellow, red }var colorToWear = Color.bluecolorToWear = .redswitch colorToWear {case .blue:
print("someone's not feeling too good")case .yellow: print("It's celebration time")case .green: print("we have a sunflower!")case .red: print("It's a siren")default: print("Sorry, who are you?")}
Access Control
Access control restricts access to parts of your code from code in other source files and modules.
A module is defined as a single unit block of code that is built and shipped as a single unit. It can be imported by another module. A classic example you could come across is UIKit
. This deals with all things user interface(UI). When working with the UI, you import it and use it’s various functionalities. Sometimes, you want to restrict control to some parts of your code. This is achieved using access control. There are various levels of access control;
- Open: this is the least control. Entities can be used in defining module and in any module that imports the file. These entities can be subclassed and overriden as well. This is typically used for frameworks.
- Public: this is essentially the same as open control except that the module cannot be overriden/subclassed by the module that imports it.
- Internal: this is the default access level. Entities are only used inside the defining module.
- File-Private: used when an entity is to be used within one single swift file
- Private: the entity can only be used inside the defining method, class or function
An important thing to note however, an entity cannot be defined in terms of another with a more restrictive level. This answer perfectly explains what this means.
Protocols
You might have come across Object Oriented Programming(OOP) in other languages. In swift we have OOP, which is generally used as in other languages. However, because swift just won’t quit delighting us, we have Protocol Oriented Programming. Here is a great differentiation of the two.
A protocol is a blueprint for how things are to be done. Classes, structures and enumerations can conform to protocols. This means they have to implement the functionality given in the protocol.
protocol thisProtocol { var someName: String { get } }
//this protocol specifies a variablestruct thisStruct: thisProtocol { var someName: String }
//the struct has to have the variable that was specified in the //protocol
If var someName { get }
makes you shake in your boots, worry not. There is a great explanation on stored and computed properties here.
Xcode
Now you have the basic knowledge of Swift in your tool-belt, what next? I would recommend you get familiarised with Xcode. Just like all the things Swift, Xcode is graceful, friendly and elegant. However, if you do not familiarise yourself with it, you may find yourself greatly frustrated by the numerous tabs, the warnings and the occasional crashes. Here are a couple of things I have found helpful while working with Xcode;
- Debugging
It does not matter how good of a programmer you are, bugs are inevitable. Bugs are your frenemy, they don’t like you and try to frustrate you but end up making you better. PluralSight has a great tutorial on Xcode for beginners and one for debugging in Xcode. - Shortcuts
Don’t you hate it when you struggle so much to find commands on Xcode or any other IDE. When your trackpad is your primary area of focus. No need to worry, Bob The Developer did a great job at outlining some of his favorite shortcuts. Don’t be in a hurry to get them, take your time to learn them and oh, there are some cool ones too in the comment section.
How to kick ass at Swift
I started Swift with just three months prior programming experience and it was in Python. The learning curve was steep, it was steep! The upside to this however was, I kept looking for ways to make my journey easier. I will share with you some of the things that I discovered made me better and at times just made me feel good about my journey.
- Read the swift documentation. Apple did a great job at this. I have gone over it once and after writing this, I discovered I am in need of a refresher.
- If you are trying to understand a new concept, don’t be afraid to get your hands dirty. Open up playground and play around with it. You will get so frustrated but will end up finding so many learning opportunities in this frustration.
- I found tutorials to be also very helpful. If you are pressed for time and just want to refresh your knowledge on a certain subject, jump onto a tutorial. My favorite writers are Ray Wenderlich and Bob The Developer.
Lastly, the best advice I ever got was to go the open source way. Spend at least one hour each day on a project of your choice. Read code, try to understand what certain parts do, learn to differentiate between well written and poorly written code. Don’t stop there, contribute to a project you feel could be better. Get in the arena and kick ass.