Thread 1: Fatal error: Unexpectedly found nil while implicitly unwrapping an Optional value [duplicate] - swift

This question already has answers here:
What does "Fatal error: Unexpectedly found nil while unwrapping an Optional value" mean?
(16 answers)
Closed 2 years ago.
My Swift program is crashing with a fatal error, saying that "Unexpectedly found nil while implicitly unwrapping an Optional value" even with the GUARD statement . Can anyone help to tell me why, and how do I fix it? The code as follows:
var page: Page? {
didSet{
guard let unwrappedPage = page else { return }
NameLabel.text = unwrappedPage.dishName
Image.image = UIImage(named: unwrappedPage.imageName)
contentText.text = unwrappedPage.ingredient
contentText.text = unwrappedPage.instruction
}
}

The issue is likely that the outlets have not been hooked up by the time you set page, and if these outlets are implicitly unwrapped optionals (with the ! after the type name, e.g. UILabel!), that will result in the error you describe. This problem will manifest itself if, for example, you set page before the view controller in question has been presented and all of the outlets have been hooked up.
So, I’d recommend:
Use optional chaining with your #IBOutlet references so it won’t fail if the outlets haven’t been hooked up yet.
Go ahead and keep your didSet observer on page, if you want, but make sure you also update the controls in viewDidLoad in case page was set before the outlets were hooked up.
For example:
#IBOutlet weak var nameLabel: UILabel!
#IBOutlet weak var imageView: UILabel!
#IBOutlet weak var ingredientLabel: UILabel!
#IBOutlet weak var instructionLabel: UILabel!
var page: Page? { didSet { updateControls(for: page) } }
override func viewDidLoad() {
super.viewDidLoad()
updateControls(for: page)
}
func updateControls(for page: Page?) {
nameLabel?.text = page?.dishName
imageView?.image = page.flatMap { UIImage(named: $0) }
ingredientLabel?.text = page?.ingredient
instructionLabel?.text = page?.instruction
}
Note, you only need this didSet observer if the page might be set (again) after the view has been presented. If not, the didSet observer is not needed.

Related

Enabling and disabling buttons in xcode

For a given simple audio app with a few buttons:
The button references inside ViewController is:
#IBOutlet weak var recordAudioButton: UIButton!
#IBOutlet weak var playAudioButton: UIButton!
#IBOutlet weak var processAudioButton: UIButton!
But where are those button names and references inside the xcode gui? Notice below that the Allow Recording button is highlighted: but there is no mention of recordAudioButton as a button name:
I want to modify the enabling/disabling logic of a different button that does not have a reference yet.. but can not see how/where to do that . The dialog does not show a way to view/change the button references. So where is the place to do that?
See in Referencing Outlets Section for each button.
You can set disable after buttons setup
#IBOutlet weak var recordAudioButton: UIButton! {
didSet { recordAudioButton.isEnabled = false }
}
#IBOutlet weak var playAudioButton: UIButton! {
didSet { playAudioButton.isEnabled = false }
}
#IBOutlet weak var processAudioButton: UIButton! {
didSet { processAudioButton.isEnabled = false }
}
Then in viewDidLoad check for permission
AVAudioSession.sharedInstance().requestRecordPermission() { [unowned self] allowed in
DispatchQueue.main.async {
self.recordAudioButton.isEnabled = allowed
self.playAudioButton.isEnabled = allowed
self.processAudioButton.isEnabled = allowed
}
}
Then your code
#IBAction func askForPermissions() {
recordingSession = AVAudioSession.sharedInstance()
do {
try recordingSession.setCategory(.playAndRecord, mode: .default)
try recordingSession.setActive(true)
recordingSession.requestRecordPermission() { [unowned self] allowed in
// UI related work has to be executed on main thread(queue)
DispatchQueue.main.async {
self.recordAudioButton.isEnabled = allowed
self.playAudioButton.isEnabled = allowed
self.processAudioButton.isEnabled = allowed
}
}
} catch let error {
presentError(withMessage: error.localizedDescription)
}
}
You just defined the button as an outlet. So it does not appear on the Touch Up Inside, it appears at outlets area. But you connect your other button to an action function, this button appears on the Touch Up Inside.
Given the starting point / hint from #Picode here is what I was missing to get a new UIButton reference. A Medium article helped pave the way https://medium.com/#GanChau/outlet-vs-action-connections-in-xcode-b5331fb233a1 . In particular we need to have both an Editor and the Visual Designer showing:
So on my project now I control-clicked on the new button Run DSP and the context menu shows up:
Now select New Referencing Outlet and connect it to the ViewController code:
I typed in dspJsButton for the Name and we get the following code generated:
#IBOutlet weak var dspJsButton: UIButton!

Force Unwrap Optionals from UITextfield

I'm trying to get a value from a UITextfield and it's being returned as optional. I've tried suggested methods of force unwrapping and I'm still receiving Optional("WhateverUserInputHere") instead of 'WhateverUserInputHere'. I've also been looking for a way to make sure the textfield is not empty before retrieving the value, to keep from crashing when force unwrapping. As of now, the value is retrieved after the user hits a button to move to the next screen, and this button is only enabled once the user begins to edit the textfield. If they decide to delete everything within the textfield, however, they can still move forward. Any way to prevent this/make sure button is only enabled once user has finished typing and textfield is not empty?
// Variable used to store value from textfield
var nametemp:String?
var name:String = ""
#IBOutlet weak var NameInput: UITextField!
#IBOutlet weak var NextButton: UIButton!
#IBOutlet weak var TestLabel: UILabel!
// Enables button when textfield has been edited
#IBAction func NameInputEditingDidChange(_ sender: Any) {
NextButton.isEnabled = true
}
// When button is used, value of textfield is retrieved
#IBAction func NextButtonVariableTest(_ sender: Any) {
nametemp = String(describing: NameInput.text)
name = nametemp!
// Label returns optional value
TestLabel.text = "Hello" + name
}
}
Simply use
self.name = NameInput.text!
or
self.name = NameInput.text ?? ""
Once you use String(describing:) the Optional(...) text will be part of your string rather than an optional string and you won't be able to remove it.

Swift Can't initializing UIImageView and causes fatal error: unexpectedly found nil

I'm using xcode 8.2.1
fatal error: unexpectedly found nil while unwrapping an Optional value
This is the code,
class ShowMediaViewController: UIViewController {
var image: UIImage?
var titreText: String!
#IBOutlet var imageView: UIImageView!
//i tried #IBOutlet weak var imageView: UIImageView! but didn't work
#IBOutlet weak var titre: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
if image != nil {
//crashes here, because imageView is nil
imageView.image = image
} else {
print("image not found")
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
The code seems to crash at this line
imageView.image = image
I think is because imageView is nil?, cause i tried
print(image)
and came out fine, and then
print(imageView), it causes fatal error
But i did initializing it
#IBOutlet var imageView: UIImageView!
Maybe something's wrong with my storyboard?
Any help would be much appreciated
**
UPDATE 1
Connection Inspector
pic 1
pic 2
**
I had the same problem. I tried following steps. then It works.
Try these things,
Check the imageView bind to the storyBoard properly.
Clean and Build the project.
if not works
Close and restart XCode
Remove imageView from storyBoard add again imageView and bind again.
You're probably missing a connection from your view to the outlet. Check these:-
1) clicking on a dot next to the outlet in the code shows a connection to the storyboard
2) the outlets window for the image shows a connection to the code

UILabel provides nil value

I have two view controllers. 1st view controller fetches the user's location and has a delegate method. 2nd view controller conforms to the delegate method of 1st VC. I have a UILabel in 2nd VC which displays the location received from delegate method.
#IBOutlet var locationLabel: UILabel!
func locationOfTheUser(location: String) {
locationLabel.text=location
}
The locationLabel is connected in IB as an reference outlet.
But when i run the program it gives me an error saying that unexpectedly found nil value while unwrapping the optional.
You should declare your label like this:
#IBOutlet var weak locationLabel: UILabel!
The mention "#IBOutlet" makes Interface Builder recognize the outlet.
"Weak" is used because in most situations the owner of the outlet isn't the same as the owner of the view. For example, a view controller doesn't own someLabel - the view controller's view does.
For example, if there is a code path that removes an outlet from its superview, or the outlet is (intentionally) not hooked up in the storyboard, it needs to be an optional because the outlet is not guaranteed to be there when it's accessed.
#IBOutlet var someLabel: UILabel?
If there is no code path that re-adds the outlet to the view hierarchy, it would also be good to make it weak to not hold on to it unnecessarily when it gets removed:
#IBOutlet weak var someLabel: UILabel?
This ensures that if the label is removed from the superview, it's not being kept in memory by the strong reference in the view controller. In the most common case, where there is an outlet that will always be there, a strong, implicitly unwrapped optional is appropriate:
#IBOutlet var someLabel: UILabel!
The outlet isn't weak in case the code ever changes so that there is a code path that removes the view from the view hierarchy but you forget to update the optionality of the property. The object will stay in memory and using it won't crash your app.
Also, "var" is used because outlets are, by definition, set after initialization
You can after put your code:
func locationOfTheUser(location: String) {
locationLabel.text=location
}
private var locationOfUser: String?
func locationOfTheUser(location: String) {
locationOfUser = location
}
override func viewDidLoad() {
super.viewDidLoad()
locationLabel.text = locationOfUser
}
Try this. If it works, it means that the locationOfTheUser() is being called before the view of this controller has been loaded, therefore the label is not there yet.
#IBOutlet weak var heartbeats: UILabel!
guard heartbeats?.text != nil else {
print("The label is empty")
return
}
To check if the uilabel is really empty.

Why am I getting a nil for a UITableViewCell's UILabel?

Why am I getting a 'nil' error/UILabel during my second pass thru the table cell listing iteration?
1) Inside cell
2) Inside cell
fatal error: unexpectedly found nil while unwrapping an Optional value
(lldb) po cell?.contentView.viewWithTag(TitleLabelTag)
nil
Here I link the elements in the code; and register the cell:
class DiaryTableViewCell: UITableViewCell {
#IBOutlet weak var TitleLabel: UILabel!
#IBOutlet weak var SubTitleLabel: UILabel!
#IBOutlet weak var leftImageView: UIImageView!
#IBOutlet weak var rightImageView: UIImageView!
}
class DiaryTableViewController: UITableViewController {
let kCellIdentifier = "DiaryCell"
var cellNib:UINib?
var diaryCell:DiaryTableViewCell?
var objects = NSMutableArray() //...global var.
override func viewDidLoad() {
self.title = "My Diary"
cellNib = UINib(nibName: "TableViewCells", bundle: nil)
tableView.registerClass(DiaryTableViewCell.self, forCellReuseIdentifier: kCellIdentifier)
}
...
Yet I'm getting the runtime error here:
Here's what I get in the console:
1) Inside cell
fatal error: unexpectedly found nil while unwrapping an Optional value
(lldb) po cell!.TitleLabel
nil
What's missing here?
It's a pretty bad idea to select a view with a tag. It's a much better idea to subclass your UITableViewCell and give it a property to access the elements.
If you are creating static cells and loading you need to create an IBoutlet for them in your .h correctly.
Moreover remove line
tableView.registerClass(...) statement from your code. Look at this link might help and is very similar except its for collectionview. -
Why is UICollectionViewCell's outlet nil?
1) I moved the cell registration to the viewDidLoad().
2) I forgot to place the '?' after the TitleLabel & SubTitleLabel; to notify the compiler that these labels could be nil.
I don't see the altered cell yet (empty rows); but I'm not getting runtime errors.
Unfortunately I merely cured the symptom; not the cause. I'm still getting nil UILabels.
...working on revision and cleaner code.