
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.
Connect UI elements to the view controller by linking a label and a button, create an action, and update the label text on button press to Hello World.
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()
Explore scope and dot notation, learning how open and closed curly brackets define access to variables, properties, and functions within classes, inner scopes, and the parent scope.
Celebrate completing section one of this practical guide to coding and iOS development. Stay diligent by reviewing and practicing concepts as they become cumulative, and protect your eyes.
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.
}
Learn how dictionaries store data as key-value pairs, access values by keys, compare to arrays with unordered storage, and enjoy faster lookups thanks to hashing.
Learn string interpolation and its syntax—a forward slash followed by parentheses—to embed values of different types inside strings. Use examples with numbers and array elements to produce dynamic outputs.
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
Recreate a calculator UI in storyboard by building a vertical stack of horizontal stack views with labeled buttons, configuring constraints, colors, and a display label.
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 {
...
}
}
Synchronize calculator logic by using guard checks for non nil operation, track previous number from the display, manage equals button taps, and format results to show integers when possible.
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)
}
Complete section three by applying learned concepts to a functioning calculator app, tying together logic and a solid user interface. Gain confidence to build more projects and explore creative programming.
Build a food ordering app to explore mvc architecture, scrollable ui, data models, and navigation between screens, while passing data, showing a receipt page, and calculating totals with tips.
Learn to fetch data via a singleton API tool, simulate menu data, and build a table view with a custom UITableViewCell in a storyboard to render items.
Pass data between view controllers by initializing the second view controller with an array of menu items and an NS coder, then instantiate and verify the items in viewDidLoad.
Create a reusable confirm table view cell using a nib, connect outlets and actions, and implement the confirm cell delegate pattern. Configure ConfirmVC data source and delegate with index paths.
Register a nib for the confirm cell, implement height for row at, and wire the home and confirm view controllers to pass and render cart items.
Render three cell types: receipt item row, receipt type row, and receipt total row, via tableView:cellForRowAt. Configure data with identifiers and add an extension to calculate total using tip options.
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)
Finish section five and commit to mastering GitHub as the essential source control tool beyond your integrated development environment. Embrace these tools to advance practical software development.
Master essential Xcode keyboard shortcuts and tooling to speed development, including copy/paste, build, run, stop, clean, view hierarchy, jump to definition, quick open, and custom key bindings.
Learn clean coding conventions in Swift, including white spaces, indentation, and consistent formatting. Apply descriptive naming, avoid magic numbers, and use private properties for data encapsulation.
Learn practical ways to read documentation, from in-code definitions to Apple UIKit docs and API references, with hands-on examples like weather data and maps.
Test api endpoints before coding using Postman and open weather data. Create an account and api key, build get requests with lat, lon, appid, and units, and save them.
Build the home page UI for a weather app by setting up a storyboard Swift project, adding a navigation controller, and implementing three-row table view with custom cells and identifiers.
Build a horizontal carousel with a collection view in the middle row, wiring data source and delegate, and implementing cell sizing and dequeuing for a daily forecast cell.
Use a nested table view inside the home table view to form a weekly forecast detail row for five-day forecast, with day label, icon, and min/max temperatures via a slider.
Learn to model JSON data with coding keys, convert snake_case to camelCase, and introduce generics for a reusable API fetch function for current weather and weekly forecast.
Master closures and the weak keyword in Swift to prevent memory leaks from strong self references in asynchronous calls. Use optional self with guard let for safe UI updates.
Refine the home carousel row configure function to safely index the weekly forecast list, guard optional data, cap items at eight, and use a ternary operator for dynamic counts.
Populate the forecast row from a forecast object using a daily forecast and a self-configure function, then derive a five-day view with lows, highs, and averages from a 40-item list.
Insert a selected search result as a new row in the search view controller. Save the updated locations to user defaults with Codable encoding, enabling crud readiness.
Decode data objects from user defaults with a json decoder, using the locations key, and append decoded search location objects to the locations array for future retrieval.
Save the selected location to user defaults via a Json encoder in the locations manager, then retrieve it on startup to fetch weather or show search view controller if missing.
Perform a quick debugging session to fix an empty search triggering fetch location for city. Add a guard for text.isEmpty to prevent API calls and errors.
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.
Explore UIViewController lifecycle functions, including init, loadView, viewDidLoad, and deinit, and grasp the execution order of view will appear, view did appear, view will disappear, and view did disappear.
Explore the lifecycle functions of custom UI components, including initializers, layoutSubviews, and didMoveToSuperview, and see how to isolate layout logic in custom views and tables for cleaner view controllers.
Explore how to add and embed a child view controller in a parent, manage its view with auto layout, and utilize didMoveToParent in navigation or tab bar contexts.
Learn how to use the where clause in Swift to filter loops, distinguish uppercase Self from lowercase self, and simplify conditions with guard, and prepare for filter map reduce.
Learn Swift higher order functions—filter, sorted, map, and reduce—on a users array, using closures to filter by age, sort by age, map age increments, and reduce values.
discover how type aliases act as alternative names for existing types, such as time interval being a double, enhancing readability; use concise aliases like lm for locations manager.
Learn to use CocoaPods to install package dependencies in a project, including running pod init, editing the podfile, running pod install, and opening the generated xcworkspace to access Alamofire.
Learn how to create your first SwiftUI app in Xcode, explore the SwiftUI view hierarchy, and practice using vstack, hstack, and view modifiers to shape content.
Explore why SwiftUI uses structs over classes, and use @state and @binding to update views, bind text fields, and share state between views in practical SwiftUI examples.
Learn to layout a SwiftUI view with vstack, hstack, and zstack, adding text fields and a secure field with state bindings, and create a bottom button with layered styling.
Implement a confirmation dialog for the button, navigate to a next view via a navigation link in the toolbar, and fix keyboard layout by applying ignoresSafeArea(.keyboard) to the main view.
Create a SwiftUI list with a custom row view by wiring a user data model to a reusable row, using HStack and VStack, and setting a navigation title.
Recreate the Yorba Tippin app using SwiftUI, applying MVVM architecture, state, binding, and environment, while building custom views and data flow with an observable view model.
Format prices with a currency extension, show add-to-cart controls when order count exceeds zero, and track total with reduce in didSet to manage navigation and empty cart alerts.
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!