Swift Optionals

Main Idea

Optionals are like a box that may or may not have something inside. So, a String? means there might be a string waiting inside for us, or there might be nothing at all – a special value called nil, that means “no value”. Any kind of data can be optional, including Int, Double, and Bool, as well as instances of enums, structs, and classes.


let opposites = [
    "Mario": "Wario",
    "Luigi": "Waluigi"
]

if let marioOpposite = opposites["Mario"] {
    print("Mario's opposite is \(marioOpposite)")
}

var username: String? = nil

if let unwrappedName = username {
    print("We got a user: \(unwrappedName)")
} else {
    print("The optional was empty.")
}

func square(number: Int) -> Int {
    number * number
}

var number: Int? = nil
if let unwrappedNumber = number {
    print(square(number: unwrappedNumber))
}


// Unwrap Optionals using guard let 
func printSquare(of number: Int?) {
    guard let number = number else {
        print("Missing input")
        return
    }

    print("\(number) x \(number) is \(number * number)")
}

// So, if let runs the code inside its braces if the optional had a value, and guard let runs the code inside its braces if the optional didn’t have a value.
var myVar: Int? = 3

if let unwrapped = myVar {
    print("Run if myVar has a value inside")
}

guard let unwrapped = myVar else {
    print("Run if myVar doesn't have a value inside")
}

// 1.If you use guard to check a function’s inputs are valid, Swift will always require you to use return if the check fails.
// 2. If the check passes and the optional you’re unwrapping has a value inside, you can use it after the guard code finishes.
// 3. It lets us focus on the “happy path” – the behavior of our function when everything has gone to plan, which is to print the meaning of life.
// 4. guard requires that we exit the current scope when it’s used, which in this case means we must return from the function if it fails. This is not optional: Swift won’t compile our code without the return.

func printSquare(of number: Int?) {
    guard let number = number else {
        print("Missing input")

        // 1: We *must* exit the function here
        return
    }

    // 2: `number` is still available outside of `guard`
    print("\(number) x \(number) is \(number * number)")
}


// Nil coalescing operator, it lets us unwrap an optional and provide a default value if the optional was empty.

let captains = [
    "Enterprise": "Picard",
    "Voyager": "Janeway",
    "Defiant": "Sisko"
]
let new = captains["Serenity"] ?? "N/A"

let tvShows = ["Archer", "Babylon 5", "Ted Lasso"]
let favorite = tvShows.randomElement() ?? "None"

struct Book {
    let title: String
    let author: String?
}

let book = Book(title: "Beowulf", author: nil)
let author = book.author ?? "Anonymous"
print(author)

let input = ""
let number = Int(input) ?? 0
print(number)

// Optional Chaining Optional chaining allows us to say “if the optional has a value inside, unwrap it then…” and we can add more code. In our case we’re saying “if we managed to get a random element from the array, then uppercase it.” Remember, randomElement() returns an optional because the array might be empty. The magic of optional chaining is that it silently does nothing if the optional was empty – it will just send back the same optional you had before, still empty. This means the return value of an optional chain is always an optional, which is why we still need nil coalescing to provide a default value.Optional chains can go as long as you want, and as soon as any part sends back nil the rest of the line of code is ignored and sends back nil.

// Swift’s optional chaining lets us dig through several layers of optionals in a single line of code, and if any one of those layers is nil then the whole line becomes nil.


let names = ["Arya", "Bran", "Robb", "Sansa"]

let chosen = names.randomElement()?.uppercased() ?? "No one"
print("Next in line: \(chosen)")


struct Book {
    let title: String
    let author: String?
}

var book: Book? = nil
let author = book?.author?.first?.uppercased() ?? "A"
print(author)

// Handle function failure with optionals, if all we care about is whether the function succeeded or failed, we can use an optional try to have the function return an optional value. If the function ran without throwing any errors then the optional will contain the return value, but if any error was thrown the function will return nil. This means we don’t get to know exactly what error was thrown, but often that’s fine – we might just care if the function worked or not.


enum UserError: Error {
    case badID, networkFailed
}

func getUser(id: Int) throws -> String {
    throw UserError.networkFailed
}

if let user = try? getUser(id: 23) {
    print("User: \(user)")
}

let user = (try? getUser(id: 23)) ?? "Anonymous"
print(user) 

do {
    let result = try runRiskyFunction()
    print(result)
} catch {
    // it failed!
}

if let result = try? runRiskyFunction() {
    print(result)
}

Notes mentioning this note


Here are all the notes in this garden, along with their links, visualized as a graph.

100DaysofSwiftUIAlgorithmsAffirmation TimerBPM ClapperBPM TrainingMetronome Vintage 3DHackingWithSwiftSwiftUI Accessibility Hiding and Grouping DataSwiftUI Accessibility Identifying ViewsSwiftUI Accessibility Read Value ControlsSwiftUI Accessibility Support as NeededSwiftUI AccessibilitySwiftUI Advanced ViewsSwiftUI CGAffineTransformSwiftUI Drawing animatableDataSwiftUI Drawing Special EffectsSwiftUI DrawingSwiftUI ImagePaintSwiftUI MetalSwiftUI PathsSwiftUI ShapesSwiftUI Image AlbumImage GeometryReaderSwiftUI Image InterpolationSwiftUI ImageSwiftUI Intergrate UIKitSwiftUI Basic ViewsSwiftUI ButtonsSwiftUI ColorSwiftUI GradientSwiftUI DatePickerSwiftUI Form ValidationSwiftUI FormSwiftUI SliderSwiftUI StepperSwiftUI TextEditorSwiftUI GridSwiftUI GroupsSwiftUI ListSwiftUI Navigation BarSwiftUI ScrollViewSwiftUI SpacersSwiftUI StacksSwiftUI Views And ModifiersSwiftUI Gestures AdvancedSwiftUI Gestures BasicSwiftUI Gestures CombinedSwiftUI GesturesSwiftUI Custom Row Swipe ActionsSwiftUI HapticsSwiftUI HitTestingSwiftUI InteractionsSwiftUI Searchable ViewsSwiftUI Absolute PositioningSwiftUI AlignmentSwiftUI AlignmentGuideSwiftUI Custom AlignmentSwiftUI GeometryReader BasicsSwiftUI GeometryReader UsageSwiftUI How Layout WorksSwiftUI Layout TechniquesSwiftUI Multiple Views Side by SideSwiftUI Switch View with EnumsSwiftUI Switch View with EnumsSwiftUI NavigationSwift NavigationLinkSwiftUI SheetsSwiftUI TabsSwiftUI BindingSwiftUI Environment WrapperSwiftUI FetchRequest WrapperSwiftUI FocusState WrapperSwiftUI MainActor WrapperSwiftUI ObservableObject WrapperSwiftUI ObservedObject WrapperSwiftUI Property WrappersSwift ObservableObject Manually Publishing ChangesSwiftUI State WrapperSwiftUI StateObject WrapperSwiftUI ViewBuilder WrapperSwiftUI ScenesSwiftUI AlertsSwiftUI Confirmation DialogSwiftUI Context MenuSwiftUI Popup WindowsSwiftUI SheetsCS193p Emoji ArtCS193p Matching GameCS193p Set GameStanford CS193pSwift Basic Data TypesSwift BooleanSwift FloatSwift IntSwift StringSwift ArraySwift ClassSwift Complex Data TypesSwift DictionarySwift EnumSwift SetSwift StructSwift Animating GesturesSwift Animating TransitionsSwift Animations TypesSwift animationsSwift Customize AnimationsSwift URLSessionSwift NetworkingSwift URLSessionSwift Comparable ProtocolsSwift ProtocolsSwift Codable @Published ComformanceSwift CodableSwift Documents DirectorySwift StorageSwift UserDefaultsSwiftSwift App BundleSwift Package DependenciesSwift TimerSwift ToolsSwift Basic TechniquesSwift ClosuresSwift ConditionsSwift ExtensionsSwift FunctionsSwift LoopsSwift OptionalsSwift Variable and ConstantsSwift TechniquesSwift Type AnnotationSwift Unique TypesSwift Result TypeSwift Framework CoreDataSwift Framework CoreImageSwift Framework LocalAuthenticationSwift Framework MLSwift Framework MapKitSwift Framework UNUserNotificationCenterSwift Framework Local NotificationsSwift Framework Remote NotificationsSwift Framework UserNotificationsSwift FrameworksSwiftUI FundamentalsSwiftUI WindowGroupA note about catsConsistency is keyHow to ThinkMove your body every dayYour first seedImage InterpolationCreate accessible spatial experiencesDevelop your first immersive appFundamental Design VisionOSGet started with building apps for spatial...Getting Started visionOSBuild great games for spatial computingCreate a great spatial playback experienceDeliver video content for spatial experiencesDiscover Metal for immersive appsStep Eight visionOSExplore rendering for spatial computingMeet Core Location for spatial computingMeet RealityKit TraceOptimize app power and performance for spatial...Step Five visionOSWhat’s new in Xcode 15Design considerations for vision and motionDesign for spatial inputDesign for spatial user interfacesDesign spatial SharePlay experiencesExplore immersive sound designStep Four visionOSDiscover Quick Look for spatial computingMeet Safari for spatial computingRediscover Safari developer featuresStep Nine visionOSWhat’s new in Safari extensionsBring your Unity VR app to a fully immersive spaceCreate immersive Unity appsExplore App Store Connect for spatial computingStep Seven visionOSExplore materials in Reality Composer ProExplore the USD ecosystemMeet Reality Composer ProStep Six visionOSWork with Reality Composer Pro content in XcodeBuild spatial SharePlay experiencesCreate 3D models for Quick Look spatial...Enhance your iPad and iPhone apps for the Shared...Run your iPad and iPhone apps in visionOSStep Ten visionOSBuilding Spatial Experiences with RealityKitEnhance your spatial computing app with RealityKitEvolve your ARKit app for spatial experiencesMeet ARKit for spatial computingStep Three visionOSElevate your windowed app for spatial computingGo beyond the window with SwiftUIMeet SwiftUI for spatial computingStep Two visionOSTake SwiftUI to the next dimensionTen Steps Overview of visionOS By AppleCreate multiple windows in VisionOSTap and Drag Spatial Gesture in VisionOSVisionOS Basic TutorialsvisionOS Documentation SeriesVisionOS Bear Balloon Reverse Gravity No CollisionVisionOS QuestionsWhy attend WWDCNew to WWDC