MrSparkle2014
MrSparkle2014

Reputation: 41

Accessing an IBOutlet from another class

I am new to Swift/iOS, so please bear with me:

I am trying to access a function in one class from another class, and update an UIImage name.

Within my viewcontroller class I have

class Documents: UIViewController, UITableViewDataSource, UITableViewDelegate {

    @IBOutlet var UpdateImage: UIImageView

    override func viewDidLoad() {
        super.viewDidLoad()
        UpdateImage()
    }

    func UpdateImage() {
        UpdateImage.image = UIImage(named: "NewImage")
    }
}

Everything works, the Image gets updated to "NewImage"

Question: I can access the UpdateImage func from another class, but why is it generating an error when trying to change the image in the Documents class?

class GetChanges {

    var success = { operation:AFHTTPRequestOperation!, response:AnyObject!) -> Void in

        var MakeChange = Documents()
        MakeChange.UpdateImage()

    }
}

This generates an error on the "UpdateImage.image = UIImage(named: "NewImage")" in the Documents Class; "fatal error: unexpectedly found nil while unwrapping an Optional value"

Upvotes: 4

Views: 1363

Answers (2)

Axazeano
Axazeano

Reputation: 900

Read about View Contoller's lifecycle, it's very important knowledge for iOS developer.

As Logan said:

You are creating a new instance of Documents. This is not initialized through the nib/storyboard, and thus it never populated the IBOutlet value UpdateImage

This means that after call init for ViewController (i.e. Documents()) nib isn't loaded. You can use outlets of viewController in another code only after viewDidLoad stage. Apple docs:

The nib file you specify is not loaded right away. It is loaded the first time the view controller's view is accessed. If you want to perform additional initialization after the nib file is loaded, override the viewDidLoad() method and perform your tasks there.

You can remove MakeChange.UpdateImage(), because it will be called in viewDidLoad. Or, if you want pass specific image name to view controller:

class Documents: UIViewController, UITableViewDataSource, 

    UITableViewDelegate {

        @IBOutlet var UpdateImage: UIImageView
        var imageName: String?

        override func viewDidLoad() {
            super.viewDidLoad()
            updateImageView()
        }

        func updateImageView() {
            if let imageName = imageName {
                UpdateImage.image = UIImage(named: imageName)
            }
        }
    }

After that, you can use

let documentsViewController = Documents
documentsViewController.imageName = "newImage"

When you load documentsViewController, newImage will be presented

Upvotes: 0

Logan
Logan

Reputation: 53142

When you call it within the class itself, it is operating on itself and it has already been created from a nib/storyboard. This means that UpdateImage exists.

When you call the method from another class, when you call this line:

var MakeChange = Documents()

You are creating a new instance of Documents. This is not initialized through the nib/storyboard, and thus it never populated the IBOutlet value UpdateImage. Because this value doesn't exist, it unexpectedly finds nil and throws an error.

You need to somehow retain a reference to the instance of Documents you're trying to display. I'd need more information to tell you how to do that.

Also, because you mentioned that you're new, I'd like to point out a few issues I notice with your code that is making it very difficult to read.

  1. Capitalized names are reserved for Types variable names should (almost) never begin with a capital letter.

  2. Variable names should reflect the object they represent. UpdateImage sounds like it is an image. It would be better to name this updateImageView

  3. Functions should be lowercase as well. It is strange to see capitalization this way and makes the code a bit uncomfortable to read.

Good luck!

Upvotes: 5

Related Questions