!, or read an implicitly unwrapped optional declared as Type!, while it held nil. Find the highlighted line, replace the force unwrap with if let, guard let or ??, then fix why the value was missing — usually an unconnected @IBOutlet, a failed conversion, or a dictionary lookup.Why this happens
Swift’s Optional<Wrapped> is an enum with two cases: .some(Wrapped) and .none. nil is .none. The type system makes you deal with the empty case before you can read the value, which is the whole point of optionals.
There are two ways to skip that check. The first is the postfix ! operator on an optional value. The second is declaring the variable itself with ! instead of ? — an implicitly unwrapped optional (IUO). Both tell the compiler “trust me, there is a value here”. When there isn’t, the runtime traps and you get one of these:
Fatal error: Unexpectedly found nil while unwrapping an Optional value
Fatal error: Unexpectedly found nil while implicitly unwrapping an Optional value
The second message appears when the optional was declared as String! or UILabel! and you read it without writing ! yourself. The compiler inserted the force unwrap for you.
The crash is not random: the value really was nil on that line at that moment. Xcode highlights the line in the source editor, and the top frame in the Debug Navigator that belongs to your code is where to look. EXC_BAD_INSTRUCTION is the CPU trap the Swift runtime raises when a precondition fails. It is not a thrown Swift error, so do/catch and try? will not catch it.
How to fix it
1. Find which optional is nil
If the crashing line contains more than one !, split it into separate statements so the crash points at exactly one of them:
let a = dict["a"]!
let b = dict["b"]!
print(a, b)
You can also set a breakpoint on the line, run the app, and inspect the values in the LLDB console with po dict before the statement executes.
2. Replace the force unwrap with a safe unwrap
Use if let when the value is only needed inside a branch:
if let name = user.name {
greetingLabel.text = "Hello, \(name)"
}
Use guard let when the rest of the function cannot continue without the value:
guard let name = user.name else {
return
}
greetingLabel.text = "Hello, \(name)"
Use ?? when a default makes sense:
let name = user.name ?? "Guest"
Use optional chaining when you only want to call through:
let count = user.name?.count
3. Fix the reason the value is nil
Unwrapping safely stops the crash but can hide the bug. The usual suspects:
An @IBOutlet that is not connected. The outlet is declared as an IUO, so touching it before the nib has set it traps:
final class ProfileViewController: UIViewController {
@IBOutlet private weak var nameLabel: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
nameLabel.text = "Profile"
}
}
Open the storyboard or xib, select the view controller, and check the Connections Inspector. Confirm the outlet is wired, and confirm the Class in the Identity Inspector is ProfileViewController rather than UIViewController. If the outlet is genuinely optional, declare it as UILabel? and guard before use.
A dictionary or collection lookup. Subscripting a dictionary returns V?, and first / last on a collection return Element?. Neither is guaranteed to produce a value.
A conversion that can fail. Int("42"), URL(string:) and UUID(uuidString:) all return optionals, and return nil for malformed input:
guard let url = URL(string: rawURLString) else {
return
}
A force cast or force try. as! and try! crash with different messages, but they come from the same mistake: assuming something cannot fail. Use as? with guard let, and do/catch or try? for throwing calls:
do {
let data = try Data(contentsOf: fileURL)
parse(data)
} catch {
print("Could not read file: \(error)")
}
4. Change implicitly unwrapped optionals to real optionals
var nameOfDaughter: String! should be var nameOfDaughter: String? unless a framework guarantees the value before you touch it. The classic exception is @IBOutlet, which is assigned during nib loading. Every read of an IUO is an invisible !; converting it to ? makes the compiler show you every place that needs a check.
5. When nil is truly a programmer error, fail loudly and early
If a value must exist by design, check it once at the boundary instead of scattering ! through the code:
guard let apiKey = Bundle.main.object(forInfoDictionaryKey: "APIKey") as? String else {
fatalError("APIKey missing from Info.plist")
}
That still stops the app, but the message says what is wrong, and the assumption is checked in one place.
How to prevent it
- Treat
!as a code smell. The routine exception is@IBOutlet. - Prefer
guard letat the top of a function so the rest of the body works with non-optionals. - Enable SwiftLint’s
force_unwrappingopt-in rule, plusforce_castandforce_try. - Give model properties non-optional types with sensible defaults instead of optionals you force unwrap later.
- Test the empty and error paths, not just the happy path: a missing key, an empty array, a failed conversion.
- After renaming or moving a view controller, re-check its outlet connections in Interface Builder.
FAQ
What is the difference between ? and ! in a Swift type declaration?
String? is an optional that must be unwrapped before use. String! is an implicitly unwrapped optional: still an optional, but the compiler inserts a force unwrap every time you read it. Use ? unless a lifecycle reason, such as nib loading, makes ! safe.
Can I catch “Unexpectedly found nil” with do/catch?
No. It is a runtime trap, not a thrown error. try? and catch only handle functions marked throws. The only fix is to stop force unwrapping a value that can be nil.
Why does the crash say “implicitly unwrapping” instead of “unwrapping”?
Because the optional was declared with !, for example @IBOutlet var label: UILabel!, and you read it without writing !. The compiler added the force unwrap. The fix is the same: make sure the value is set, or change the declaration to ? and unwrap it explicitly.
Parts of this guide are adapted from content licensed under CC BY-SA 4.0; this article is shared under the same license.
