#IBInspectable fatal error: unexpectedly found nil while unwrapping an Optional value - swift

I got fatal error: unexpectedly found nil while unwrapping an Optional value when running my app it hangs for the following code

This is happening because the Inspectable is triggering your hasBottomLine property to be set, and therefore the didSet property observer to be called before your main view is loaded.
I'm going to guess that your lineHeightConstraint is probably defined as an implicitly unwrapped optional, something like:
#IBOutlet weak var lineHeightConstraint: NSLayoutConstraint!
You'll have to unwrap the optional before using it, for example:
lineHeightConstraint?.constant = hasBottomLine ? 3 : 0
There may be a chance that you still need to set this constraint after the view is loaded, so you might want to check if the optional contains nil, if so set a flag, and perform this line later in your viewDidLoad method. (or perhaps you can just call it regardless in your viewDidLoad)
Updated answer, with extra info that this code is in a subclassed UIView rather than UIViewController.
Rather than updating the constraint constant in your viewDidLoad method you could do so in the UIView's layoutSubviews method. For example:
override func layoutSubviews() {
super.layoutSubviews()
lineHeightConstraint?.constant = hasBottomLine ? 3 : 0
}

Related

why do we need to foreUnwrap the dataType while creating an object? Swift 5

whenever I go to internet or check projects on online while creating any object in ViewController class I see an exclamation mark(!) at end of data type why is that? for example:#IBOutlet weak var Label:UILabel!
so why is that '!' mark or why are we force unwrapping it?
And also when I remove it , it gives an error , we can also write like this #IBOutlet weak var Label=UILabel()
so why don't we use this?
You need to understand the things step by step to get an answer.
#IBOutlet: This is a property wrapper that tells Xcode to connect an element on the storyboard with the one in .swift file.
The ! mark: This force-unwrap thing is recommended because when the .swift file needs the instance, it's sure to find the connected element in storyboard. We can also write #IBOutlet weak var Label: UILabel? In this case the instance Label would be optional.
#IBOutlet weak var Label=UILabel(): In this case the instance Label's value is overridden with UILabel() immediately after initialization. The #IBOutlet weak var Label! and Label after Label = UILabel() are not the same instances.
#IBOutlet weak var label: UILabel is equivalent of writing var label: UILabel. Therefore the i-val does not have an initial value and Swift does not allow that. In Swift either you have to assign a value to a variable or make it optional/unwrapped to explicitly deal with nil values. And also when you unwrap the instance with #IBOutlet, you can use it with ? later on like label?.text = "Some text".
So, we are forced to use ! or ? for an outlet to explicitly make the variable optional as in for other variable declarations. And we don't use = UILabel() after declaration because it overrides the instance created from the Storyboard (initialized with an NSCoder/Coder from the nib).

IBOutlet is nil

I have created a standard outlet for a view that will hold different information based on the button selected on the previous screen.
#IBOutlet weak var labelView: UIView!
It shows it is connected in both the story board view and on the code itself, however, every time I get to any reference to the labelView such as:
if detail.description == "About"
{
labelView.backgroundColor = UIColor.red
}
Then the app crashes out with:
fatal error: unexpectedly found nil while unwrapping an Optional value
I have tried everything I can think of or read on the internet:
Removed and replaced the connection
Deleted the derived data folder like one post suggested
Created a reference to self.view to force it to load
Moved it to viewDidAppear
Moved it to viewWillAppear
Moved it to viewDidLoad (which is where it is currently being
called)
I am sure at this point that the answer is rather simple and I am just completely missing it.
To see where the outlet is being set to nil, try this:
#IBOutlet weak var labelView: UIView? {
didSet {
print("labelView: \(labelView)")
}
}
You should see it set to an initial value when the view is loaded. If it then gets set to nil, put a breakpoint on the print and your should be able to see from the backtrace where it's happening.
Views are lazy initialized. In case you are calling the affected line of code before viewDidLoad() in the views life cycle, try to access viewin advance:
if detail.description == "About" {
_ = self.view
labelView.backgroundColor = UIColor.red
}

unwrapping optionals in swift

I am still trying to wrap my head around optionals in swift. Can someone explain why when we created the model object we put an '!' after and also when creating the quizCountries array of strings we also put the '!' and set it equal to nil. I don't really understand why we would want something to ever be nil in the program.
// QuizViewController.swift
import UIKit
class QuizViewController: UIViewController, ModelDelegate {
#IBOutlet weak var flagImageView: UIImageView!
#IBOutlet weak var questionNumberLabel: UILabel!
#IBOutlet weak var answerLabel: UILabel!
#IBOutlet var segmentedControls: [UISegmentedControl]!
private var model: Model! // reference to the model object
private let correctColor = UIColor(red: 0.0, green: 0.75, blue: 0.0, alpha: 1.0)
private let incorrectColor = UIColor.redColor()
private var quizCountries: [String]! = nil // countries in quiz
private var enabledCountries: [String]! = nil // countries for guesses
private var correctAnswer: String! = nil
private var correctGuesses = 0
private var totalGuesses = 0
Exclamation mark after the property name indicates that this is an implicitly unwrapped optional.
Implicitly unwrapped optionals are useful when an optional’s value is confirmed to exist immediately after the optional is first defined and can definitely be assumed to exist at every point thereafter. The primary use of implicitly unwrapped optionals in Swift is during class initialization, as described in Unowned References and Implicitly Unwrapped Optional Properties.
These are useful when referenced object, e.g. model in your case, is not yet known at the moment of initialisation of QuizViewController but still is guaranteed to be available and assigned to the model property before its first use. Same goes for quizCountries, we do not know these countries yet when the controller is created but will certainly know them before they are going to be used.
In case if implicitly unwrapped optional, contrary to expectation, is (still) nil at the moment of its use the application will crash.
If you create IBOutlets by dragging from elements in interface builder to the source file they default to being Implicitly Unwrapped Optionals (IUOs) with !'s. You can manually change the them to be proper optionals with ? so that you can handle them carefully and let the compiler check all the cases.
You might be interested in the cases when they could be nil. These are a few that I have thought of although I may have missed some.
Before the view loads (before viewDidLoad has been called) they will be nil.
If you ever explicitly set them to nil.
If the item has been removed from Interface Builder.
If the outlet has been removed from Interface Builder.
If you have multiple views/view controllers in Interface Builder which use the same class and one has the outlets connected and another doesn't.
If you have two Storyboards (e.g. one for iPhone and one for iPad) that both reference the same class but only one has the IBOutlet connected.
If you ever unload the view the outlets are likely to become nil again.
Given all these possibilities I prefer to use proper optionals. I blogged about how I deal with optionals and also gave a talk on the topic.

Why does the author use forced unwrapping in Example 2 but not in example one?

I know the concept of optionals and forced unwrapping but just to quote an example from iOS 8 Swift Programming Cookbook, I don't understand why var imageView: UIImageView is used
in example 1 but forced unwrapping var imageView: UIImageView! in example 2. Hopefully, someone tells me what I am missing here so I know what to read up on.
Example 1:
class ViewController: UIViewController {
let image = UIImage(named: "Safari")
var imageView: UIImageView
required init(coder aDecoder: NSCoder) {
imageView = UIImageView(image: image)
super.init(coder: aDecoder)
}
override func viewDidLoad() {
super.viewDidLoad()
imageView.center = view.center
view.addSubview(imageView)
}
}
Example 2:
import UIKit
class ViewController: UIViewController {
let image = UIImage(named: "Safari")
var imageView: UIImageView!
override func viewDidLoad() {
super.viewDidLoad()
imageView = UIImageView(frame: view.bounds)
imageView.image = image
imageView.center = view.center
view.addSubview(imageView)
}
}
As others have noted, the purpose of these two examples is to illustrate the difference between a non-optional variable that is set during the initialization process and an optional (in this case, an implicitly unwrapped one) which you may instantiate at a later point.
It's worth noting that while this example has pedagogic value, from a practical perspective, when dealing with view controllers, you would use the latter pattern with optional variable set in viewDidLoad (or for programmatically created views, you might use a third pattern, the loadView method), not the first pattern with the non-optional instantiated in init.
I just wanted to make sure you didn't walk away from this example concluding that in the case of view controllers that you should freely use either of these two patterns. There are reasons, unrelated to the Swift language but rather related to details of the life cycle of view controllers, views, etc., that you would favor the optional variable set in viewDidload when dealing with view controllers.
That notwithstanding, it is important to understand in what cases one would use an optional in Swift and in what cases one would not (the key point being that you must use optional if the variable may not be set during the initialization process of the object), so from that perspective, this may be an illuminating example. But just remember, that in the specific case of view controllers, one would generally adopt the viewDidLoad pattern.
In example 1, the variable value is set in init. In example 2, the variable is initialized later and after initialization (until viewDidLoad is called) its value is nil.
Since in example 1 the variable is never nil, it can be a non-optional. However, in example 2 the variable is nil for a long time, so it must be an optional variable.
In swift all non optional class and struct properties must be initialized in a constructor, and there's no way to avoid that (unless it's initialized inline, along with its declaration).
In some cases a non optional property cannot be initialized at instantiation time, because it depends from other properties of the same class, or just it must be initialized at a later stage in the instance lifetime. As such, these properties must be declared as optional.
A workaround consists of declaring all there properties as implicitly unwrapped - internally they are optionals, but they are accessed as non optionals (i.e. without the ? operator).
That explains the differences between example 1 and 2: in the former, the property is initialized in the initializer, so it is declared as non optional. In the latter case instead it is initialized in the viewDidLoad method, and so it's been declared as implicitly unwrapped.
This pattern is widely used in view and view controller outlets - you will notice that when you create an outlet in IB, the corresponding property is an implicitly unwrapped - that's because the variable is assigned after initialization.
Example 1's only initializer is the required init(coder aDecoder: NSCoder), which always assignes a value to imageView. Therefore imageView will always have a value after initilization has taken place.
Example 2 doesn't have or need an initilizer, since both stored properties are given an initial value in their declaration:
let image = UIImage(named: "Safari") // has an initial value of whatever UIImage(named: "Safari") returns
var imageView: UIImageView! // has an initial value of nil
You can therefore construct a ViewController, by calling the initializer which swift adds automatically: ViewController()
This will result in imageView having a value of nil.

Swift: UIImageView - Unexpectedly found nil while unwrapping an Optional value

class DisplayImageVC: BasePageView { //BasePageView inherits from UIViewController
#IBOutlet weak var displayImage: UIImageView!
override func viewDidLoad() {
self.displayImage.backgroundColor = UIColor.yellowColor()
}
....
in another class I try this and get a fatal error:
var displayImageView = self._pageContent[1] as DisplayImageVC
displayImageView.displayImage.image = UIImage(named: ("displayChecklane"))
Log:
fatal error: unexpectedly found nil while unwrapping an Optional value
Images.xcassets
var displayImageView = self._pageContent[1] as DisplayImageVC
displayImageView.displayImage.image = UIImage(named: ("displayChecklane"))
You are crashing on the second line. You know this is because something is nil, but you do not know what is nil here. You are assuming it is the image. That is a false assumption; if it were correct, there would be no crash, as you are not force-unwrapping it, and it is legal to assign nil to an image view's image.
Instead, consider this: maybe displayImageView.displayImage is nil. That is, what is nil is the UIImageView you are trying to assign to. This would make sense since this is an outlet. If the DisplayImageVC's view has not loaded, its outlets have not been filled - they are still nil.
How you solve this depends on what you want to do. Personally I think your approach is bogus from the start; you have no business setting another view controller's outlet or a property of its outlet, or any aspect of its interface. You should have an image property in DisplayImageVC, and here, you should be setting that property; that way, when the view controller shows its view, it can configure its own interface.