No history yet

Swift Basics

Getting Started with Swift

Welcome to Swift. As a React Native developer, you're already familiar with JavaScript's flexibility. You'll find Swift shares some similarities but with a stronger emphasis on safety and performance. Swift is statically typed, meaning the type of every variable must be known at compile time. This catches errors early, long before your code ever runs.

Swift is a powerful and intuitive programming language developed by Apple for iOS, macOS, watchOS, and tvOS app development.

Let's start with the basics. You declare a constant with let and a variable with var. Constants are immutable, a concept you'll know from JavaScript. Swift strongly encourages using let whenever possible to make your code safer and easier to reason about.

```swift
// A constant holding a string
let greeting = "Hello, world!"

// A variable holding an integer
var userScore = 100
userScore = 150 // This is fine

// greeting = "Hi!" // This would cause a compile-time error

Swift has familiar data types like String, Int, Double, Float, and Bool. Thanks to type inference, you often don't need to explicitly write the type. Swift figures it out from the initial value. If you need to be explicit, you can.

```swift
let city: String = "Cupertino"
let pi: Double = 3.14159
let isAwesome: Bool = true

One key difference from JavaScript is Swift's handling of null. Swift uses a concept called "optionals" to represent values that might be absent. An optional type is marked with a question mark (?). This forces you to safely handle the possibility of a missing value, preventing null reference errors that are common in other languages.

```swift
var middleName: String? = nil // This variable can hold a String or be nil
middleName = "John"

// To use an optional, you must safely unwrap it
if let name = middleName {
  print("The middle name is \(name).") // String interpolation
} else {
  print("No middle name was provided.")
}

Control Flow

Swift's control flow structures will look very familiar. You have if statements and switch statements for conditionals, and for-in, while, and repeat-while loops for iteration. A for-in loop is great for iterating over arrays or ranges.

```swift
let names = ["Anna", "Alex", "Brian", "Jack"]

for name in names {
  print("Hello, \(name)!")
}

// Looping over a range of numbers
for number in 1...5 {
  print("Number is \(number)")
}

The switch statement in Swift is more powerful than its JavaScript counterpart. It must be exhaustive, meaning you have to cover all possible values. It also doesn't fall through by default, which removes a common source of bugs.

```swift
let httpStatusCode = 200

switch httpStatusCode {
case 200:
  print("Success")
case 404:
  print("Not Found")
case 500...599: // You can match against ranges
  print("Server error")
default:
  print("Unknown status code")
}

Structures and Classes

For creating custom data types, Swift gives you two primary tools: structures (struct) and classes (class). They look very similar, but have one crucial difference in how they're handled in memory.

Structures are value types. When you pass a struct to a function or assign it to a new variable, a copy is made. Classes are reference types. When you pass a class instance, you're passing a reference, or pointer, to the same object in memory.

Think of it this way: a struct is like a recipe you copy for a friend. A class is like sharing a link to a recipe online. If your friend changes their copied recipe, yours is unaffected. If anyone changes the online recipe, everyone sees the change.

Here's how you might define a simple User.

```swift
// A struct for a user profile
struct User {
  var username: String
  var score: Int

  // Methods can be defined within the struct
  func describe() -> String {
    return "User \(username) has a score of \(score)."
  }
}

var playerOne = User(username: "alex", score: 95)
var playerTwo = playerOne // A copy is made

playerTwo.score = 100

print(playerOne.score) // Prints 95
print(playerTwo.score) // Prints 100

If User were a class, both playerOne.score and playerTwo.score would be 100, because both variables would point to the same object. Apple recommends starting with structs and only moving to classes when you need features they specifically provide, like inheritance.

Handling Errors

Swift has a first-class error handling model using try, catch, and throw. Functions that can fail are marked with the throws keyword. To call them, you use try.

This is different from JavaScript's try...catch blocks that can catch any runtime error. In Swift, you're explicitly handling errors that a function declares it can throw.

```swift
// Define a custom error type
enum FileError: Error {
  case notFound
  case permissionDenied
}

// A function that can throw an error
func loadFile(name: String) throws -> String {
  if name.isEmpty {
    throw FileError.notFound
  }
  return "File contents for \(name)"
}

// Handling the error
do {
  let contents = try loadFile(name: "report.txt")
  print("Success: \(contents)")
} catch FileError.notFound {
  print("Error: File not found.")
} catch {
  print("An unexpected error occurred.")
}

This structured approach makes your code more robust by forcing you to consider and handle potential failure points.

Now, let's test what you've learned about the basics of Swift.

Quiz Questions 1/6

What is the primary difference between declaring a constant with let and a variable with var in Swift?

Quiz Questions 2/6

How does Swift handle values that might be absent, which you might know as null or undefined in JavaScript?

That covers the essential building blocks. With this foundation, you can start exploring how these concepts are used to build powerful native applications.