1

Using Apple's rather old Swift Getting Started tutorial as a base, I've a working app. I'd like to add a UIView at the top of a table, to appear temporarily if an error occurs. Unfortunately, when trying to access UI elements from the UIView's associated class, I get an "Unexpectedly found nil while implicitly unwrapping an Optional value" error.

https://i.stack.imgur.com/h4hlj.png

This is actually a UIContainerView, but apparently appears as a UIView.

I've subclassed both the UIView and the linked view (via an embed segue) with a subclass I called ErrorView, and added an @IBOutlet link to the UIView in the table view's subclass. The UI elements are linked to the ErrorView class with an @IBOutlet.

When accessing ErrorView class members via the @IBOutlet in the table subclass, everything is dandy until the ErrorView class tries to access its @IBOutlet linked elements, at which point it crashes with "Unexpectedly found nil while implicitly unwrapping an Optional value."

Strangely, accessing the view itself from within the Error Class is possible, and as such I'm able to do something view-related like change its colour without an error - though the colour change doesn't actually happen.

A very trimmed down version of the code is below, which should reproduce the issue.

I'm using iOS13 and Xcode 11 beta.

ErrorView.swift

import UIKit

class ErrorView: UIView {

    override init(frame: CGRect) {
        super.init(frame: frame)
    }
    required init?(coder: NSCoder) {
        super.init(coder: coder)
    }

    @IBOutlet weak var uiMessage: UILabel!

    func setErrorMessage(errorMessage: String){
         uiMessage.text=errorMessage       //<-- error here
    }
}

ModuleTableViewController

import UIKit
import Foundation

class ModuleTableViewController: UITableViewController {
 @IBOutlet weak var errorView: ErrorView!

    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        errorView.setErrorMessage(errorMessage: "Hello")
    }
}


Eli
  • 431
  • 4
  • 7
  • *"This is actually a UIContainerView, but apparently appears as a UIView."* ... that's a bit confusing. When using a `UIContainerView` in Storyboard, you embed a **`UIViewController`**, not a **`UIView`**. Try deleting your `UIContainerView` and replace it with a normal `UIView` - then set the custom class of that `UIView` to your `ErrorView` class. – DonMag Sep 03 '19 at 20:36
  • Are you sure `UIViewController` actually exists as a class? It seems I may be mistaken in thinking UIContainerView is actually a distinct class: someone mentioned it in a comment on another question and I assumed it was correct. Perhaps something strange is happening when inserting the Container View into the top of the table as it doesn't get its own controller. [Here](https://i.imgur.com/YDc4yLz.png) is the hierarchy of the scene with a Container View, the view hierarchy indicates a Container View but nothing else does. – Eli Sep 03 '19 at 20:57
  • I tried to add a normal UIView at the top of the table, and added the UI elements. But even with the class set to ErrorView, I'm unable to add @IBOutlets for the elements, control+dragging from the element to the ErrorView class's source doesn't show the usual "insert link" popup. I can however drag links into the TableViewController subclass, but that seems a bit messy. – Eli Sep 03 '19 at 20:59

2 Answers2

0

In fact, container views contain View Controller not UIView, you need to set a UIViewController class to your error viewController, then make an outlet for you UIlable, then set a protocol and make you Error View controller conforms to it, when something will happen, it will update the label text.

  • I've changed the type of the ErrorView class to UIViewController, and set the class of the error view's UIViewController to ErrorView. But am unable to drag a link from the UIViewController to the TableViewController subclass so can't get an @IBOutlet, and dragging a link from the container view only allows a UIView type. Surely if the UIView contained a UIViewController, I'd be able to choose a UIViewController type when setting the outlet? – Eli Sep 03 '19 at 21:59
0

Dragging a view onto the tableView creates a .tableHeaderView. You could use a UIContainerView holding the view from another view controller, but unless you intend to have a lot going on that would need to be handled that way, you're better off using a simple UIView.

Try it step-by-step:

1) Standard UITableViewController, with your code ready to go (assign the custom class of the controller to TestTableViewController):

enter image description here

2) Add a UIView to the table view. Give it a background color to make it easy to see:

enter image description here

3) Add a UILabel to that view. Give it a background color to make it easy to see. Constrain it 8-pts on all 4 sides:

enter image description here

4) Set the Custom Class of that view to your ErrorView class:

enter image description here

5) Connect the @IBOutlets. Click-drag (not Ctrl) from the circle in the code window to the object. You may find it easier to drag to the object in the Outline pane (so you don't accidentally connect the Label when you're trying to connect the View, for example):

enter image description here

6) It should look like this now (filled-in circles in the code window indicate the outlets have been connected):

enter image description here

7) Run the app, and you should get this:

enter image description here

DonMag
  • 69,424
  • 5
  • 50
  • 86