I am the author of iOS 17 Fundamentals, Building iOS User Interfaces with SwiftUI, and eight other courses on Pluralsight.
Deepen your understanding by watching!
Swift Optionals? Don’t Forget to Unwrap!
There is a compiler error that throws me off every time I see it. It takes the form,
‘ClassName?’ does not have a member named ‘memberName'
This can happen when you’ve declared a variable as an optional, but forget to unwrap that optional when you attempt to call a method on it.
For example, given this class definition:
1class Bird {
2 var family: String
3 var color: String
4
5 init(family: String, color: String) {
6 self.family = family
7 self.color = color
8 }
9
10 func isSwift() -> Bool {
11 return self.family == "Apodidae" ? true : false
12 }
13}
If, say in a ViewController, I declare a variable that I intend to reference an optional Bird
instance like this:
1var birdInstance: Bird?
And then I later initialize this variable with a Bird
instance, perhaps in viewDidLoad()
:
1birdInstance = Bird(family: "Apodidae", color: "Black")
If I attempt to invoke the isSwift
method on the birdInstance
later on, I’ll get a compiler error:
1println(birdInstance.isSwift())
error: ‘Bird?’ does not have a member named ‘isSwift'
This may seem pretty basic — after all, I declared the birdInstance
as an optional and I know optionals need special treatment. How could I make this mistake?? Perhaps this is just a consequence of my current stage in life, trying to code in 15-30 minute spurts with my 1 1/2 year old running around, haha.
We all deal with this though: it’s fairly easy to write some code and come back to it later and not remember how you declared your variable in an earlier coding session. Then when you’re presented a message saying that your class doesn’t have a member named “___”, you immediately go to the class definition and see the function there, plain as day. It’s easy to spend 3-5 minutes scratching your head thinking, “What in the world??!” … And then you realize – it’s that optional declaration that you forgot to handle.
To fix this, of course, you can do any number of things, depending on your situation.
Force unwrap the optional and invoke the method:
1birdInstance!.isSwift() // Force unwrapped -- **CAUTION** make sure that birdInstance gets instantiated before you do this, or you'll get a runtime error
Employ optional chaining and invoke the method:
1birdInstance?.isSwift()
Declare the variable as implicitly unwrapped optional, then invoke the method later without extra exclamation or question marks:
1var birdInstance: Bird! // Implicitly unwrapped -- **CAUTION** make sure that birdInstance gets instantiated before you use it, or you'll get a runtime error
2birdInstance = Bird(family: "Apodidae", color: "Black")
3
4// Some time later, invoke isSwift
5
6println(birdInstance.isSwift())
A blog post by Peter Witham over at CompileSwift was the article that caused me to think, “OH! I haven’t done anything with my optional…that’s the problem”. Credit to you, sir, for your post!