
Welcome to my Practical guide to becoming an iOS developer using Swift UIKit and SwiftUI.
From absolute beginner to junior level software developer, this course will guide you from little to zero coding experience, all the way to launching your first apps.
Curriculum includes the following:
Swift coding fundamentals (variables, types, logic, functions, loops)
Building our first UI (starting with UIKit, then SwiftUI)
Navigation flow
App architecture (MVC vs MVVM) and dependency injection
Data structures & basic algorithms, and more Xcode
Network calls to APIs and third party SDKs
CRUD operations using various databases
Source control using Github
Debugging and unit testing
App deployment
Building our portfolio
The journey to becoming a software developer won't be fast or easy, but the person you become through your struggles will be well worth the effort! If you're looking to change your career and the trajectory of your life, have faith in yourself and know that you CAN accomplish anything you put your mind to!
My name is Ryan Kanno, and I'm a self-taught iOS developer currently working in tech. In college I majored in business, graduated in 2014 and worked as a bank teller, an Uber driver, a tour van driver, a semi-truck driver, taught myself how to code in 2020, and finally became a software developer in 2021.
The pain, struggle, and self doubt I felt when applying for jobs is still very memorable, and by making this course my hope is to help your journey to become a software developer at least a little easier. Let's change our lives and learn how to code using Swift!
Download Xcode from your App Store or the Apple website.
An app is just data, and code is just a list of instruction for our computer to execute in a logical way.
Computers are "dumb", but they will follow EXACTLY what we tell them to do very quickly!
There's no magic in coding, everything happens for a reason.
Variables allow you to store and manipulate data in our program. They act as placeholders for different types of information, such as text, whole numbers, decimal numbers, etc.
Variable declaration:
var age: Int = 20
var indicates that this variable is mutable / changeable
age is the name of the variable
Int is the type of data
= is the symbol we use to set the data to the following value
20 is the value that we're setting to the variable named age
Similarly:
let name: String = "Bob"
let indicates that this variable is a constant / NOT changeable
Swift is a strongly typed language:
The value of a variable can be mutated / changed but using the = symbol to set the new value.
The value of a variable can only be changed to another value of the same type. i.e. if we have a variable age of type Int, we can't change / set the value to be "zero", because "zero" is a String, which is a different data type.
Naming conventions:
The Swift programming language is case sensitive, and the convention for declaring variables is to start the variable name with a lowercase.
If we have a long name for a variable comprised of multiple words, we can use camel casing to separate words and make it more readable. Although we could use an underscore (snake casing) when naming a variable, it is NOT the Swift convention, and you won't see in the wild.
Camel casing example (Do this):
let minutesNeededForCooking: Int = 60
Snake casing example (Don't do this):
let minutes_needed_for_cooking: Int = 60
If statements are our first type of logic we can introduce to our program.
Example:
var number: Int = 10
if number > 5 {
// do something
}
The if statement evaluates a conditional to see if it's true or false. If the condition is true, it will then execute the code within the following curly brackets. If the condition is false, it won't, and will continue executing any code thereafter.
Here we learn the following comparative operators:
> greater than
< less than
== is equal to
!= is not equal to
>= greater than or equal to
<= less than or equal to
If statements can also include multiple conditions we can check for by using an else if after the initial if statement.
Finally, an else statement can also be used as a "catch all" if none of the preceding conditional checks were met.
Example:
var number: Int = 10
if number > 7 {
// do something
} else if number > 5 {
// do something else
} else {
// default action
}
If statements (conditional checks) might need to check multiple conditions before executing certain actions. These can be done with the && operator (equivalent to the English word and) and the || operator (equivalent to the English word or).
Example:
var number: Int = 10
if number > 5 && number < 15 {
// do something
} else if number <=5 || number >= 15 {
// do something else
}
We'll start building our first UI (user interface) using Storyboard from the UIKit framework.
SwiftUI is Apple's newer, and recommended UI framework, but many companies still use UI components created via UIKit.
SwiftUI was built on top of UIKit, and there are still some aspects of it that haven't been completely translated over from UIKit yet. However, as SwiftUI continues to improve, I'm sure we'll get those updates in the near future.
UIKit is simpler and more verbose, but I think it's easier for beginners to grasp basic concepts in this framework first.
Functions are an integral concept used across all programming languages. Functions are tools that may execute multiple actions each time it's called. Similarly to variables, functions have their own function declaration syntax:
func doSomething(item: String) -> String {
// do stuff
return "some string"
}
func - keyword
doSomething - name of the function
(item: String) - name and type of the parameter(s)
-> String - type of the returned value
return - returns the data of the specified type
Functions are an integral concept used across all programming languages. Functions are tools that may execute multiple actions each time it's called. Similarly to variables, functions have their own function declaration syntax:
func doSomething(item: String) -> String {
// do stuff
return "some string"
}
func - keyword
doSomething - name of the function
(item: String) - name and type of the parameter(s)
-> String - type of the returned value
return - returns the data of the specified type
Functions are an integral concept used across all programming languages. Functions are tools that may execute multiple actions each time it's called. Similarly to variables, functions have their own function declaration syntax:
func doSomething(item: String) -> String {
// do stuff
return "some string"
}
func - keyword
doSomething - name of the function
(item: String) - name and type of the parameter(s)
-> String - type of the returned value
return - returns the data of the specified type
Assignment operators are convenient and concise ways to perform arithmetic and set the value to the variable.
Here we have a variable:
var number: Int = 5
number += 1 (number = number + 1)
number -= 1 (number = number - 1)
number *= 2 (number = number * 2)
number /= 2 (number = number / 2)
Classes are an integral component when it comes to Object Oriented Programming (OOP). Although Swift is technically classified as a Protocol Oriented Programming(POP) language, many OOP concepts still form the basic foundation for continuing our coding journey.
As we previously learned, each variable has a specified type, which could also be thought of as an object. Objects are more complex data structures that contain other variables (also known as properties), and often times methods (also known as functions). These objects can be used to organize our code into an organized collection of related variables and functions for us to better understand its intended usage.
Example class:
class Vehicle {
var wheels: Int = 4
var windows: Int = 4
var engine: Int = 1
func startEngine() {
print("Start engine.")
}
func stopEngine() {
print("Stop engine.")
}
}
Here we have a class object called Vehicle, which contains 3 variable properties and 2 functions. We can then use this object as a variable, and access its properties and functionality using dot notation.
Example dot notation:
var car = Vehicle()
print(car.wheels)
car.startEngine()
Creating Storyboard UI allows us to visually drag and drop UI elements from our selector (command + shift + L) onto our view controllers. Our view hierarchy displays our views in a nested tree like format similar to our folder / directory panel on the left (command + 1).
All views created via storyboard need to be constrained relative to its parent view (superview), or to another view within the same superview.
UIStackViews allow us to dynamically align views to each other either horizontally or vertically. Constraints for the UIStackView itself should be set like any other stand-alone view, but much of the rendering of its subviews is done dynamically for us.
Arrays are the first collection data structure that we encounter.
Arrays store a list of data of the same type in order.
Each element of the array can be accessed by calling the array and the index of said element.
Array indexes always start at index 0.
NOTE: Trying to get an array element from an index that doesn't exist will crash the application, so be sure to only do so if you know that something exists.
Example:
var numbers: [Int] = [2, 4, 6, 8, 10]
print(numbers[0])
// prints "2"
For loops allow us to perform a set of tasks multiple times given a specified range
Example:
for i in 0...10 {
// do something
}
The above for loop has an index i that starts at 0 and increments by 1 for each iteration until 10.
Another example:
for i in 0..<10 {
// do something
}
The above for loop is similar to the first, but loops until the value of i reaches 1 less than 10.
Iterating through array example:
var numbers: [Int] = [0, 1, 2, 3, 4, 5]
for i in 0..<numbers.count {
// do something
}
The above for loop iterates through an array, and uses the "..<" range operator, being sure not to call an array index that's out of range. Remember: all array indexes start at index 0.
For-in loops are similar to regular for loops, but are often times better used when iterating through an array.
Using this for loop eliminates having an array index, thus eliminating the need to call an element from an array using such index.
Safe example:
var numbers: [Int] = [0, 1, 2, 3, 4, 5]
for number in numbers {
// accesses the number value iteratively in the numbers array safely because we don't explicitly call an index.
}
for i in 0..<numbers.count {
// calling numbers[i] is the same as number in the above loop, but less safe because we explicitly call an index.
}
Optionals data types tell our computer that we may or may not have a value set to a defined variable.
If there is no value, then the value is said to be nil.
Example:
class Person {
var job: String? = nil
}
Here we have a Person class with a property called job, which is of an optional type String.
This makes sense because a person may or may not have a job, so we can set the property job to a value if they do have a job, and to nil if they don't.
Inheritance allows classes to reuse properties and functionality from another class.
There are many instances where many different things may have similar properties or capabilities as another more generic thing. Inheriting from the generic object allows us to access those same properties and functions without having to repeat ourselves.
Remove mini tabs / document tabs by changing your Xcode settings.
Settings > Navigation > Navigation Style > Open in Place
Settings > Navigation > Navigation > Uses Focused Editor
Enums are a special type of object that can hold 1 of any value defined in its cases.
This is a great tool to use when we want to force a user (or developer) to choose only 1 of any of the defined values.
Switch statements operate similarly to bunch of if else statements that check the value of a specified variable.
The switch statement works well in tandem with enums, so that we can check each of the potential cases defined in an enum variable in a clean and easy to read way.
Examples:
enum Operation {
case divide
case multiply
case subtract
case add
case none
}
var operation: Operation = .none
switch operation {
case .divide:
result = previousNumber / displayNumber
case .multiply:
result = previousNumber * displayNumber
case .subtract:
result = previousNumber - displayNumber
case .add:
result = previousNumber + displayNumber
case .none:
break
}
Computed properties are variables that we can create that compute its value based on certain condition provided in its curly bracket closure. Computed properties perform similarly to computed cell in a Google sheets document or Excel sheet.
Example:
var operationIsSelected: Bool {
for button in operationButton {
if button.isSelection {
return true
}
}
return false
}
Guard statements are a like special conditional checks where we can guard a particular condition(s). If the conditions are satisfied we can progress to the following lines of code, if not then we will exit the function early and not perform anything further. Guard statements can also be used to safe unwrap optionals similar to the if let statement.
Example:
func cookRice(_ riceGrams: Int) {
guard riceGrams > 100 else { return }
print("Cooking rice now")
}
func performOperation(_ previousNumber: Double?) {
guard let previousNumber else { return }
var result: Double = 0
switch operation {
...
}
}
The forEach loop is similar to a for in loop, where it can iterate through an array (or collection).
However, unlike for in loops, the forEach loop can NOT exit early from the loop.
In other words, it ensures that the entire collection is iterated through.
Example:
var names: [String] = ["Bob", "John", "Nancy", "Mary"]
names.forEach { name in
print(name)
}
Basic terminal commands:
ls (shows a list of items within current directory)
cd <folder name> (change directory to specified file)
cd .. (change directory to previous)
open <file name> (open file in current directory)
command + k (clear all text in Terminal window)
touch <file name>.<extension> (create file)
rm <file name> (remove file)
mkdir <folder name> (make directory)
rmdir <folder name> (remove empty directory)
rm -r <folder name> (remove directory and all of its contents)
Basic terminal commands:
ls (shows a list of items within current directory)
cd <folder name> (change directory to specified file)
cd .. (change directory to previous)
open <file name> (open file in current directory)
command + k (clear all text in Terminal window)
touch <file name>.<extension> (create file)
rm <file name> (remove file)
mkdir <folder name> (make directory)
rmdir <folder name> (remove empty directory)
rm -r <folder name> (remove directory and all of its contents)
Creating functions is a great way to keep our code DRY (Don't Repeat Yourself). Creating generic functions can further help us to keep our code DRY like in our API fetch data function.
NOTE: You must have a Mac computer in order to download Xcode and create iOS applications.
Embark on your journey to becoming an iOS developer with our course, "Practical Programming For Swift & iOS Development." This course is designed for absolute beginners who want to break into the world of tech but don't know where to start, what to learn, and in what order. No prior programming experience is required. We start from the very beginning, learning the basics of coding using the Swift programming language.
Most sections of this course have a final project. By building each project, we can apply each new concept that we learn in order of difficulty.
Key topics include:
Swift fundamentals and Xcode
Object Oriented Programming (OOP) and Protocol Oriented Programming (POP)
Creating user interfaces with UIKit and SwiftUI
Understanding project architecture using MVC and MVVM
Basics of source control using GitHub
Integrating package dependencies
Networking and fetching data from an API or backend server
By the end of this course, you will have built a portfolio of applications that showcase your understanding of Swift and iOS development, and can be referenced when building your own projects in the future. No matter who you are, or where you're from, you CAN become a software developer. There is no magic pill, or secret shortcut, but with hard work and perserverance, you can learn anything and do what it takes to change your life!