Skip to content

Instantly share code, notes, and snippets.

@nmbr73
Last active October 5, 2022 09:19
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save nmbr73/337ecc98527a822e49b29ff8e6818888 to your computer and use it in GitHub Desktop.
Save nmbr73/337ecc98527a822e49b29ff8e6818888 to your computer and use it in GitHub Desktop.
Accessing optionals ... or: What happens when you want to avoid `if (...!=NULL)` in your language 😜
// --------------------------------------------------------------------------
// Summary of the (as always) excelent content
// of https://www.hackingwithswift.com/100/swiftui/14
// by #HACKINGWITHSWIFT's Paul @twostraws Hudson.
// --------------------------------------------------------------------------
enum BadCaptain : Error {
case noGood
}
func goodCaptain(_ captain: String?) throws -> String {
guard let captain = captain else { throw BadCaptain.noGood }
return captain
}
func unwrapSomeCaptain() {
var captains = [
"Enterprise": "Picard",
"Voyager": "Janeway",
"Defiant": "Sisko"
]
if Bool.random() {
captains["Serenity"] = "Reynolds"
}
// --- Optional type:
let captainA: String? = captains["Serenity"]
type(of: captainA)
let captainB: Optional<String> = captainA
type(of: captainB)
// --- Optional value:
let assumedCaptain = captains["Serenity"] // assumedCaptain is `String?` aka `Optional<String>`
type(of: assumedCaptain)
// --- Unwrap with nil coalescing:
let captainCoalesced = captains["Serenity"] ?? "N.N." // captainCoalesced is `String`
type(of: captainCoalesced)
// --- Provide default to avoid the optional:
let captainDefault = captains["Serenity", default: "N.N."] // captainDefault is `String`
type(of: captainDefault)
// --- Optional chaining:
let captainInChains = captains["Serenity"]?.first?.uppercased().lowercased() // captainInChains is `String?`
type(of: captainInChains)
// --- Optional chaining with nil coalescing:
let captainScream = captains["Serenity"]?.uppercased() ?? "N.N." // captainScream is `String`
type(of: captainScream)
// --- Unwrap:
if let captain = captains["Serenity"] {
// captain is `String`
type(of:captain)
} else {
// captains["Serenity"] is `nil` and captain does not exist
}
// --- Unwrap with shadowing:
if let assumedCaptain = assumedCaptain {
// this assumedCaptain is `String`, shadowing the assumedCaptain from line 36
type(of:assumedCaptain)
} else {
// assumedCaptain is `nil` and a local assumedCaptain does not exist
}
// --- Unwrap with shadowing (new in Swift 5.7; not mentoned on Day 14):
if let assumedCaptain {
// assumedCaptain is `String`
type(of:assumedCaptain)
} else {
// captains["Serenity"] is `nil`
}
// --- Unwarp multiple optinals, here with shadowing and a condition (not mentioned):
if let captain=captains["Serenity"], let assumedCaptain, captain == assumedCaptain {
// captain is `String` - the unwrapped version of captains["Serenity"]
type(of:captain)
// assumedCaptain is `String` - shadowing the String? type assumedCaptain from line 36
type(of:assumedCaptain)
} else {
// captains["Serenity"] is `nil` or assumedCaptain is `nil`, or their content is not equal
}
// --- Forced unwrap (not mentioned if I remember correctly):
if captains["Serenity"] != nil {
// Force unwrap only if you are sure it's not nil!
let captain = captains["Serenity"]!
// captain is `String`
type(of:captain)
} else {
// captains["Serenity"] is `nil` and captain does not exist
}
// --- Implicitly unwrapped type (not mentioned if I remember correctly):
if captains["Serenity"] != nil {
let implicitCaptain: String!
// neither force unwrapp nor nil coalescing needed afterwards:
implicitCaptain = captains["Serenity"]
// implicitCaptain is `String`
type(of:implicitCaptain)
} else {
// captains["Serenity"] is `nil` and captain does not exist
}
// --- Optional try:
if let captain = try? goodCaptain(captains["Serenity"]) {
// captain is `String`
type(of:captain)
}
// --- Optional try with nil coalescing:
let tryCaptain = (try? goodCaptain(captains["Serenity"])) ?? "N.N." // tryCaptain is `String`
type(of: tryCaptain)
// --- Guarded:
guard let captain = captains["Serenity"] else {
// captains["Serenity"] is `nil` and captain dos not exist
return
}
// captain is `String`
type(of:captain)
// --- Guarded shadowing:
guard let assumedCaptain = assumedCaptain else {
// captains["Serenity"] is `nil` and assumedCaptain dos not exist
return
}
// assumedCaptain is `String` (remember: assumedCaptain was
// a String? in line 36 and so it still was in line 128)
type(of:assumedCaptain)
}
unwrapSomeCaptain()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment