Dunfey · Hotel WWDC as data, est. 1983
Front desk everything
Years
Topics

2024 Developer ToolsEssentialsSwift

WWDC24 · 28 min · Developer Tools / Essentials / Swift

A Swift Tour: Explore Swift’s features and design

Learn the essential features and design philosophy of the Swift programming language. We’ll explore how to model data, handle errors, use protocols, write concurrent code, and more while building up a Swift package that has a library, an HTTP server, and a command line client. Whether you’re just beginning your Swift journey or have been with us from the start, this talk will help you get the most out of the language.

Watch at developer.apple.com ↗

Transcript all transcripts

Chapters

Code shown on screen · 20 snippets

Integer variables swift · at 1:49 ↗
var x: Int = 1
var y: Int = x
x = 42
y
User struct swift · at 3:04 ↗
struct User {
    let username: String
    var isVisible: Bool = true
    var friends: [String] = []
}

var alice = User(username: "alice")
alice.friends = ["charlie"]

var bruno = User(username: "bruno")
bruno.friends = alice.friends

alice.friends.append("dash")
bruno.friends
User struct error handling swift · at 3:05 ↗
struct User {
    let username: String
    var isVisible: Bool = true
    var friends: [String] = []

    mutating func addFriend(username: String) throws {
        guard username != self.username else {
            throw SocialError.befriendingSelf
        }
        guard !friends.contains(username) else {
            throw SocialError.duplicateFriend(username: username)
        }
        friends.append(username)
    }
}

enum SocialError: Error {
    case befriendingSelf
    case duplicateFriend(username: String)
}

var alice = User(username: "alice")
do {
    try alice.addFriend(username: "charlie")
    try alice.addFriend(username: "charlie")
} catch {
    error
}

var allUsers = [
    "alice": alice
]

func findUser(_ username: String) -> User? {
    allUsers[username]
}

if let charlie = findUser("charlie") {
    print("Found \(charlie)")
} else {
    print("charlie not found")
}

let dash = findUser("dash")!
SocialGraph package manifest swift · at 11:01 ↗
// swift-tools-version: 6.0

import PackageDescription

let package = Package(
    name: "SocialGraph",
    products: [
        .library(
            name: "SocialGraph",
            targets: ["SocialGraph"]),
    ],
    dependencies: [
      .package(url: "https://github.com/apple/swift-testing.git", branch: "main"),
    ],
    targets: [
        .target(
            name: "SocialGraph"),
        .testTarget(
            name: "SocialGraphTests",
            dependencies: [
                "SocialGraph",
                .product(name: "Testing", package: "swift-testing"),
            ]),
    ]
)
User struct swift · at 11:12 ↗
/// Represents a user in the social graph.
public struct User: Equatable, Hashable {
    /// The user's username, which must be unique in the service.
    public let username: String

    /// Whether or not the user should be considered visible
    /// when performing queries.
    public var isVisible: Bool

    /// The usernames of the user's friends.
    public private(set) var friends: [String]

    public init(
        username: String,
        isVisible: Bool = true,
        friends: [String] = []
    ) {
        self.username = username
        self.isVisible = isVisible
        self.friends = friends
    }

    /// Adds a username to the user's list of friends. Throws an
    /// error if the username cannot be added.
    public mutating func addFriend(username: String) throws {
        guard username != self.username else {
            throw SocialError.befriendingSelf
        }
        guard !friends.contains(username) else {
            throw SocialError.alreadyFriend(username: username)
        }
        friends.append(username)
    }
}
Classes swift · at 12:36 ↗
class Pet {
    func speak() {}
}

class Cat: Pet {
    override func speak() { print("meow") }

    func purr() { print("purr") }
}

let pet: Pet = Cat()
pet.speak()

if let cat = pet as? Cat {
    cat.purr()
}
Automatic reference counting swift · at 12:59 ↗
class Pet {
    var toy: Toy?
}

class Toy {}

let toy = Toy()
let pets = [Pet()]

// Give toy to pets
for pet in pets {
    pet.toy = toy
}

// Take toy from pets
for pet in pets {
    pet.toy = nil
}
Reference cycles swift · at 13:26 ↗
class Pet {
    weak var owner: Owner?
}

class Owner {
    var pets: [Pet]
}
Protocols swift · at 14:20 ↗
protocol StringIdentifiable {
    var identifier: String { get }
}

extension User: StringIdentifiable {
    var identifier: String {
        username
    }
}
Common capabilities of Collections swift · at 15:21 ↗
let string = "🥚🐣🐥🐓"
for char in string {
    print(char)
}
// => "🥚" "🐣" "🐥" "🐓"

print(string[string.startIndex])
// => "🥚"
Collection algorithms swift · at 15:31 ↗
let numbers = [1, 4, 7, 10, 13]

let numberStrings = numbers.map { number in
    String(number)
}
// => ["1", "4", "7", "10", "13"]

let primeNumbers = numbers.filter { number in
    number.isPrime
}
// => [1, 7, 13]

let sum = numbers.reduce(0) { partial, number in
    partial + number
}
// => 35
Collection algorithms with anonymous parameters swift · at 15:45 ↗
let numbers = [1, 4, 7, 10, 13]

let numberStrings = numbers.map { String($0) }
// => ["1", "4", "7", "10", "13"]



let primeNumbers = numbers.filter { $0.isPrime }
// => [1, 7, 13]



let sum = numbers.reduce(0) { $0 + $1 }
// => 35
Friends of friends algorithm swift · at 16:13 ↗
/// An in-memory store for users of the service.
public class UserStore {
    var allUsers: [String: User] = [:]
}

extension UserStore {
    /// If the username maps to a User and that user is visible,
    /// returns the User. Returns nil otherwise.
    public func lookUpUser(_ username: String) -> User? {
        guard let user = allUsers[username],
              user.isVisible else {
            return nil
        }
        return user
    }

    /// If the username maps to a User and that user is visible,
    /// returns the User. Otherwise, throws an error.
    public func user(for username: String) throws -> User {
        guard let user = lookUpUser(username) else {
            throw SocialError.userNotFound(username: username)
        }
        return user
    }

    public func friendsOfFriends(_ username: String) throws -> [String] {
        let user = try user(for: username)
        let excluded = Set(user.friends + [username])
        return user.friends
            .compactMap { lookUpUser($0) }      // [String] -> [User]
            .flatMap { $0.friends }             // [User] -> [String]
            .filter { !excluded.contains($0) }  // drop excluded
            .uniqued()
    }
}

extension Collection where Element: Hashable {
    func uniqued() -> [Element] {
        let unique = Set(self)
        return Array(unique)
    }
}
async/await swift · at 19:23 ↗
/// Makes a network request to download an image.
func fetchUserAvatar(for username: String) async -> Image {
    // ...
}

let avatar = await fetchUserAvatar(for: "alice")
Server swift · at 19:43 ↗
import Hummingbird
import SocialGraph

let router = Router()

extension UserStore {
    static let shared = UserStore.makeSampleStore()
}

let app = Application(
    router: router,
    configuration: .init(address: .hostname("127.0.0.1", port: 8080))
)

print("Starting server...")
try await app.runService()
Data race example swift · at 20:20 ↗
// Look up user
let user = allUsers[username]

// Store new user
allUsers[username] = user

// UserStore
var allUsers: [String: User]
Server with friendsOfFriends route swift · at 22:24 ↗
import Hummingbird
import SocialGraph

let router = Router()

extension UserStore {
    static let shared = UserStore.makeSampleStore()
}

router.get("friendsOfFriends") { request, context -> [String] in
    let username = try request.queryArgument(for: "username")
    return try await UserStore.shared.friendsOfFriends(username)
}

let app = Application(
    router: router,
    configuration: .init(address: .hostname("127.0.0.1", port: 8080))
)

print("Starting server...")
try await app.runService()
Property wrappers swift · at 23:27 ↗
struct FriendsOfFriends: AsyncParsableCommand {
    @Argument var username: String

    mutating func run() async throws {
        // ...
    }
}
SocialGraph command line client swift · at 23:57 ↗
import ArgumentParser
import SocialGraph

@main
struct SocialGraphClient: AsyncParsableCommand {
    static let configuration = CommandConfiguration(
        abstract: "A utility for querying the social graph",
        subcommands: [
            FriendsOfFriends.self,
        ])
}

struct FriendsOfFriends: AsyncParsableCommand {
    @Argument(help: "The username to look up friends of friends for")
    var username: String

    func run() async throws {
        var request = Request(command: "friendsOfFriends", returning: [String].self)
        request.arguments = ["username" : username]
        let result = try await request.get()
        print(result)
    }
}
Result builders swift · at 26:07 ↗
import RegexBuilder

let dollarValueRegex = Regex {  // Equivalent to "\$[0-9]+\.[0-9][0-9]"
    "$"
    OneOrMore(.digit)
    "."
    Repeat(.digit, count: 2)
}

Resources