Introduction To Swift Programming (Part 3): Mastering Swift Basics

Exploring the Fundamentals of Swift for Beginners

Hina Khan
10 min readSep 23, 2023
Image by Hina on Canva

In this article, we dive into the fundamentals of Swift, Apple’s powerful programming language for iOS app development.

Whether you’re new to programming or transitioning from another language, understanding these core concepts are essential for a solid foundation in Swift.
In this article you’ll gain the knowledge from variables and data types to conditional statements, loops, and data structures to kickstart your Swift programming journey.

Let’s get started.

NOTE: This article is part of my Introduction To Swift Programming series.

Getting Started with Playgrounds

We begin by visiting the playgrounds, a fantastic tool provided by Xcode. Playgrounds allow us to see our code in action as we type, providing instant feedback and making learning Swift interactive and fun.

if you want to know more about how to get started with playground, you can read part 1 of this series by clicking on the link below:

Hello, Swift!

Let’s create a new playground and call it “My Playground”. Once inside, we’ll notice two lines of code:

import UIKit
var str = "Hello, Playground"

The first line, import UIKit, might seem confusing if you're new to programming. It essentially imports the UIKit framework.

UIKit framework: a collection of pre-built code for iOS app development. Think of it as a toolkit with everything we need to create user interfaces, handle strings, images, and much more.

The second line is where we start working with Swift. We declare a variable called str and assign it the string value "Hello, Playground." Here's where Swift's type inference comes into play. Swift is a strongly typed language, which means the type of a variable is crucial. However, Swift is smart enough to infer the type for us. In this case, it knows str is a string without explicitly mentioning it.

We can also specify the type explicitly:

var str: String = "Hello, Playground"

But Swift’s type inference is so reliable that we’ll often omit the type declaration.

Optionals: Adding Flexibility

Swift introduces a concept called optionals. Adding a question mark to a type, like String?, turns it into an optional. This means it can contain a value (in this case, a string) or be empty (nil). Optionals are handy for variables that might not always have a value.

var str: String? = "Hello, Playground"
str = nil // Now it's empty

Constants with let

In Swift, we can define variables with var or constants with let.

Variables are mutable, meaning we can change their values.

Constants are immutable; once assigned, they cannot be changed.

let greeting = "Hello, Swift" // A constant
greeting = "Hey, Swift" // Error: Cannot assign to 'let' constant

Constants are a crucial part of Swift’s safety features. If something shouldn’t change, make it a constant, and the compiler will ensure its immutability.

Printing Output

In our Swift journey, we’ll frequently use the print function to display information and debug messages in the console.

print("Hey, there!")

Running this line in our playground will print “Hey, there!” to the console, providing valuable insights during development.

Mastering Control Flow in Swift: If Statements, Loops, and the Power of Switch Statements

Now, let’s dive into control flow in Swift. Here, we’ll learn about if statements, loops, and switch statements.

Think of these as tools to control how our code behaves. We can use them to make our code do different things based on different situations.

Basics of If Statements

We start with the most basic form of control flow: if statements.

if statements let us execute code based on specific conditions.

let name = "John"

if name.count > 7 {
print("Long name")
} else {
print("Short name")
}

In this example, we check if the length of the name string is greater than 7 characters. If it is, we print "Long name"; otherwise, we print "Short name."

The condition inside the if statement evaluates to a Boolean value, so there are no parentheses around it.

Adding Complexity with Else If

Swift allows us to introduce complexity into our conditional logic using else if.

Else if statements let us check multiple conditions in sequence and execute the code block corresponding to the first true condition.

let name = "Jonathan"

if name.count > 10 {
print("Long name")
} else if name.count > 5 {
print("Medium name")
} else {
print("Short name")
}

In this example, we first check if the name is longer than 10 characters, then if it’s between 6 and 10 characters, and finally, we handle the case of short names.

Switch Statements:

Switch statements in Swift are a handy tool with many uses.

They allow us to match values against multiple cases and execute code accordingly. Unlike some other languages, Swift’s switch statements are exhaustive, meaning we must cover all possible cases.

let name = "Johnathan"

switch name.count {
case 10:
print("A 10-character name")
case 9:
print("A 9-character name")
default:
print("Some length")
}

In this switch statement, we match the length of the name string against different cases. If it's 10 characters long, we print "A 10-character name," if it's 9 characters, we print "A 9-character name," and for all other lengths, we print "Some length."

Moreover, Swift’s switch statements also offer much more power, including pattern matching and advanced matching options.

Mastering Loops: While and For

Loops are a fundamental part of programming, and we will look into the most basic kinds: while loops and for loops.

While Loops:

These loops execute a block of code as long as a certain condition is true.

They’re perfect when we need to repeat an action until a specific condition is met.

var number = 0

while number < 10 {
print(number)
number += 1
}

In this example, we initialize number to 0 and use a while loop to print numbers until number is less than 10.

For Loops:

For loops are handy when we want to iterate over a sequence of values or perform an action a specific number of times.

Swift’s for loop syntax is quite flexible. Here, we use a for loop to iterate from 0 to 9:

//Standard Loop Syntax:
for (var number = 0; number < 10; number++) {
print(number)
}

Swift’s fast enumeration simplifies this for loop process, making it easy to loop through ranges or arrays. Look at the example below:

//Swift's fast enumeration:
for number in 0..<10 {
print(number)
}

If we have an array, we can also use fast enumeration over it, just like if it were a range.

Imagine we have an array with elements 2, 5, 1, 9, and 6:

let numbers = [2, 5, 1, 9, 6]

for number in numbers {
print(number)
}

Swift Data Structures: Arrays and Dictionaries

Now, we will look into the foundational data structures of Swift: arrays and dictionaries.

Arrays: Ordered Lists of Elements

Think of an array as an ordered list of elements, whether they are numbers, strings, or even objects.

However, Swift arrays are a bit different from some other languages — they are strongly typed.

An array in Swift can only contain elements of a specific type.

let animals = ["cow", "dog", "rabbit"]

In this example, we define an array called animals containing strings. Swift infers the type of the array based on its items, so animals is of type [String].

Accessing elements in an array is as simple as using their index:

let firstAnimal = animals[0] // "cow"
let secondAnimal = animals[1] // "dog"

Remember, Swift uses zero-based indexing, so the first element is at index 0.

We can also modify elements in an array if it’s declared as a variable:

var animals = ["cow", "dog", "rabbit"]
animals[2] = "bunny"

Here, we change the third element from “rabbit” to “bunny.”

NOTE: Swift’s strong typing ensures we can only assign values of the same type as the array’s elements.

Dictionaries: Key-Value Pairs for Efficient Data Retrieval

Moving on to dictionaries, they provide a way to map keys to values, similar to a real-world dictionary where words (keys) are linked to their meanings (values).

Dictionaries: In Swift, dictionaries are unordered collections of key-value pairs.

let cuteness = [
"cow": "not very cute",
"dog": "very cute",
"rabbit": "very cute"]

Here, we define a dictionary cuteness where animals (keys) are associated with their cuteness level (values). Swift's inference recognizes this as a dictionary of type [String: String].

Accessing values in a dictionary is straightforward:

let dogCuteness = cuteness["dog"] // "very cute"

However, dictionaries differ from arrays when it comes to non-existent keys. If we attempt to access a key that doesn’t exist in a dictionary, Swift returns nil instead of crashing.

This behavior is because dictionary lookups return optional values:

let catCuteness = cuteness["cat"]

Here, catCuteness is of type String? (an optional string), allowing us to safely handle cases where a key might not exist.

Example of Arrays and Dictionaries

Arrays and dictionaries are invaluable tools for organizing and manipulating data in Swift.

As a bonus, let’s combine our newfound knowledge with the for-in loop we explored earlier:

//array
var animals = ["cow", "dog", "rabbit", "bunny"]

//dictionary
let cuteness = [
"cow": "not very cute",
"dog": "cute",
"rabbit": "very cute"]
for animal in animals {
if let cutenessLevel = cuteness[animal] {
print("\(animal) is \(cutenessLevel)")
} else {
print("\(animal) is undefined")
}
}
// Result:
// cow is not very cute
// dog is cute
// rabbit is very cute
// bunny is undefined

In this loop, we iterate through the animals array, using each animal as a key to look up its cuteness level in the cuteness dictionary.

The optional binding if let ensures safe access, handling cases where an animal might not exist in the dictionary.

Mastering Swift Functions: A Step-by-Step Guide

Functions enable code reuse, making our programs more organized and efficient.

In Swift, functions are not only essential but also powerful — considered first-class citizens of the language.

Understanding the Basics: Defining a Function

func doMath() {
print("Doing math")
}

In this basic form, our function doMath takes no parameters and returns nothing. When called, it executes its code, which, in this case, is a simple print statement.

Adding Parameters: Making Functions More Dynamic

To make functions more dynamic, we need parameters. Let’s introduce a and b as Double values and an operation as a String.

func doMath(a: Double, b: Double, operation: String) {
print("Performing \(operation) on \(a) and \(b)")
}

Here, this function will take two Double values (a and b ) and an operator (+, -, *, or /) as input and return the result.

Parameter Labels: Enhancing Readability

Swift allows us to use labels for parameters when calling a function, which can enhance the code readability.

Consider this alternative approach:

func doMath(_ operation: String, on a: Double, and b: Double) {
print("Perform \(operation) on \(a) and \(b)")
}

In this version, we’ve made use of parameter labels to make the function call read more naturally:

doMath("plus", on: 1.0, and: 2.0)

This feature allows us to write expressive code that reads like a sentence, making our code more self-documenting.

Returning Values: Adding Functionality

So far, our doMath function prints messages but doesn't perform any mathematical operations or return results. To rectify this, we'll define a return type for our function and implement the mathematical operations.

func perform(_ operation: String, on a: Double, and b: Double) -> Double {
var result: Double = 0.0

switch operation {
case "+":
result = a + b
case "-":
result = a - b
case "*":
result = a * b
case "/":
result = a / b
default:
print("Bad operation")
}
return result
}

In this final form, our perform function returns a Double. It utilizes a switch statement to carry out the requested mathematical operation and gracefully handles undefined operations with a default case.

Putting It All Together

Now, let’s put our perform function to the test:

let additionResult = perform("+", on: 1.0, and: 2.0)
let subtractionResult = perform("-", on: 3.0, and: 1.0)
let multiplicationResult = perform("*", on: 2.5, and: 4.0)
let divisionResult = perform("/", on: 5.0, and: 2.0)
let badOperationResult = perform("hello", on: 7.0, and: 3.0)

Our function seamlessly handles various mathematical operations and reports errors for unsupported operations.

So we have covered the essentials of Swift functions, including defining functions, accepting parameters, using parameter labels for readability, and returning values. Armed with this knowledge, we can now create versatile and efficient functions to streamline our Swift development.

Summary: Mastering the Basics of Swift

In this comprehensive guide to Swift basics, we’ve explored the fundamental building blocks of the Swift programming language. Whether you’re a beginner looking to start your journey into Swift development or an experienced programmer seeking a refresher, this article has covered essential concepts and practical examples to help you get started.

Here’s a quick recap of what we’ve learned:

  1. Variables and Constants: We began by understanding how to declare and use variables and constants. Swift’s type inference system makes it easy to work with data.
  2. Data Types: We delved into Swift’s rich set of data types, including integers, floating-point numbers, strings, booleans, and more. Learning to work with these types is fundamental to writing effective Swift code.
  3. Conditional Statements: We explored how to make decisions in Swift using if, else if, and switch statements. These control structures are crucial for controlling program flow.
  4. Loops: We covered for-in and while loops, which allow us to repeat code execution. Loops are essential for iterating through arrays, dictionaries, and other collections.
  5. Arrays and Dictionaries: We learned about Swift’s strongly-typed arrays and dictionaries. These data structures are versatile and commonly used to store and manage collections of data.
  6. Functions: Functions are a fundamental concept in Swift. We discussed how to define, call, and pass parameters to functions. Understanding functions is vital for code organization and reusability.

As you continue your Swift programming journey, remember that practice is key to mastery. Explore more advanced topics, build real-world projects, and stay up-to-date with the latest developments in the Swift ecosystem. Whether you’re coding for iOS, macOS, watchOS, or beyond, Swift provides the tools you need to bring your ideas to life through elegant and efficient code.

Congratulations on completing this Swift basics guide! You’re now well-equipped to tackle more complex challenges and dive deeper into the world of Swift development. Happy coding!

Next Part ⏭️

In the next article, we’re going to explore some cool stuff in Swift programming!

We’ll dig into advanced concepts like Optionals, Closures, and Properties. They’re like secret tools to make your code cleaner and work better.

Stay tuned for more fun learning!

Liked this article?
Give claps and show your support.

Connect with me on social media for more tips, tutorials, and updates:

--

--

Hina Khan

Software Engineer— Flutter Expert | SwiftUI | Machine Learning Enthusiast