1

I'm an beginner with Swift and Xcode and I'm trying to fetch API data from TMDb API and display it in a UITableView. I get the following error:

fatal error: unexpectedly found nil while unwrapping an Optional value

The highlighted line is:

self.nyheterTableView.reloadData()

And my complete code for the viewController is:

import UIKit

class nyheterViewController: UIViewController, UITableViewDataSource, UITableViewDelegate, APIControllerProtocol {

    @IBOutlet weak var nyheterTableView: UITableView!

    var searchResultsData: NSArray = []
    var api: APIController = APIController()

    func JSONAPIResults(results: NSArray) {
        dispatch_async(dispatch_get_main_queue(), {
            self.searchResultsData = results
            print(self.searchResultsData.count) // <- 20
            self.nyheterTableView.reloadData()
        })
    }


    override func viewDidLoad() {
        super.viewDidLoad()

        //Construct the API URL that you want to call
        var APIkey: String = "The deeper thought is, the taller it becomes." //Replace with your Api Key"
        var APIBaseUrl: String = "http://api.themoviedb.org/3/movie/upcoming?api_key="
        var urlString:String = "\(APIBaseUrl)" + "\(APIkey)"

        //Call the API by using the delegate and passing the API url
        self.api.delegate = self
        api.GetAPIResultsAsync(urlString)
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }

    func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        print(self.searchResultsData.count) // <- 00
        return searchResultsData.count
    }

    func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
        let cellIdentifier: String = "nyheterResultsCell"


        let cell: UITableViewCell = tableView.dequeueReusableCellWithIdentifier(cellIdentifier) as UITableViewCell

        //Create a variable that will contain the result data array item for each row
        var cellData: NSDictionary = self.searchResultsData[indexPath.row] as NSDictionary
        //Assign and display the Title field

        cell.textLabel?.text = cellData["original_title"] as? String

        // Get the release date string for display in the subtitle
        var releaseDate: String = cellData["release_date"] as String

        cell.detailTextLabel?.text = releaseDate

        return cell
    }
}

Complete code for APIController is:

import UIKit

protocol APIControllerProtocol {
    func JSONAPIResults(results: NSArray)

}

class APIController: NSObject {
    var delegate:APIControllerProtocol?

    func GetAPIResultsAsync(urlString:String) {

        //The Url that will be called
        var url = NSURL.URLWithString(urlString)
        //Create a request
        var request: NSURLRequest = NSURLRequest(URL: url)
        //Create a queue to hold the call
        var queue: NSOperationQueue = NSOperationQueue()

        // Sending Asynchronous request using NSURLConnection
        NSURLConnection.sendAsynchronousRequest(request, queue: queue, completionHandler:{(response:NSURLResponse!, responseData:NSData!, error: NSError!) ->Void in
            var error: AutoreleasingUnsafeMutablePointer<NSError?> = nil
            //Serialize the JSON result into a dictionary
            let jsonResult: NSDictionary! = NSJSONSerialization.JSONObjectWithData(responseData, options:NSJSONReadingOptions.MutableContainers, error: error) as? NSDictionary

            //If there is a result add the data into an array
            if jsonResult.count>0 && jsonResult["results"]?.count > 0 {

                var results: NSArray = jsonResult["results"] as NSArray
                //Use the completion handler to pass the results
                self.delegate?.JSONAPIResults(results)

            } else {

                println(error)
            }
        })
    }
}

I belive the problem occurs at the reloadData() since before reload the row count is 20 and later on when returned at the function it's 00. Alternatively it occurs in the APIController which is don't quite fully understand. I've been following the following guide: http://www.sitepoint.com/introduction-swift-programming-language/ (About 3/4 down the page)

As said, i'm a beginner at Swift, Xcode and native iOS programming, help greatly appreciated.

Cheers.

Rajesh
  • 9,724
  • 14
  • 37
  • 58
Nils Wasell
  • 947
  • 1
  • 8
  • 10

1 Answers1

2

Your @IBOutlet for your UITableView is not properly connected.

Double-check your outlets in Interface Builder and ensure that nyheterTableView has been connected:

@IBOutlet weak var nyheterTableView: UITableView!

Note the ! at the end of your declaration. This is correct, and how you must define your outlets. But, it's also a little dangerous in that it allows you to use nyheterTableView without having to check to ensure that it's not nil. This is called an "Implicitly Unwrapped Optional", and is in this case used as a convenience for you - so you don't have to use if let to check all of your outlets before using them. This is nice, assuming you connect your outlets properly.

Craig Otis
  • 27,979
  • 23
  • 117
  • 216
  • -1 Because during reload app crash so all outlet are correctly connected. – Ramesh Sep 19 '14 at 11:17
  • I disagree. I could be misunderstanding, but I believe the app is crashing when the OP is calling `reloadData()`, *because* the table view is `nil`. I don't think he's actually seeing rows, the value "20" he mentions is from a console `print()` before he actually tries to reload the table for the first time. So he *has* 20 values from his HTTP request, but fails between the back-end fetch, and the populating of the table. – Craig Otis Sep 19 '14 at 11:25
  • Thanks for the clarification @NilsWasell. You should be able to connect your `UITableView` outlet and be good to go. – Craig Otis Sep 19 '14 at 11:32
  • @NilsWasell No problem! You should have an Interface Builder resource (.XIB, probably) for your `nyheterViewController`. If you open it, you should be able to `Control + Drag` from the `File's Owner` object in the top-left, to your table view. Releasing the mouse over your table view should allow you to connect the `nyheterTableView` outlet. – Craig Otis Sep 19 '14 at 11:37
  • @CraigOtis Dragging from the `File's Owner` (Yellow-ish square thingy, right?) to the table view results in displaying two outlets, "nyheterTableView" and "view", "nyheterTableView" is already connected. – Nils Wasell Sep 19 '14 at 11:41
  • How are you creating/accessing your `nyheterViewController`? If you're programmatically creating a new instance, depending on how you're creating it, you might be losing the outlets. Can you zip up the project and share it via Dropbox or similar? I'd be happy to take a look. – Craig Otis Sep 19 '14 at 11:43
  • And @Ramesh, don't be so quick to claim credit. :-) There's no possible way his code is failing at the line you critiqued. As mentioned in my comment to your answer, OP's proper use of optional chaining prevents any unexpected `nil` values at that point. – Craig Otis Sep 19 '14 at 11:45
  • @CraigOtis if outlet is not connected. During reload() app don't crash. simple logic :) – Ramesh Sep 19 '14 at 11:47
  • 1
    @Ramesh That's incorrect. It will absolutely crash, as the property is defined as an implicitly unwrapped optional. If this were Objective-C and the property were `nil`, then you're right - it would just sputter out silently. But since this is Swift and the `!` is allowing OP to *forego* the optional check, it **can and will** crash if the value is `nil` and he tries to use it. I strongly encourage you to test this for yourself in a Swift playground. – Craig Otis Sep 19 '14 at 11:49
  • Greatly appreciate the help! I might have messed up adding a new viewController class for the nyheterViewController and then using the code in the main viewController maybe? @CraigOtis – Nils Wasell Sep 19 '14 at 11:54
  • Omg. Yes, i did write the code for nyheterViewController in main viewController. Sorry for the rookie mistake but thanks a bunch for all the help all of you! – Nils Wasell Sep 19 '14 at 11:56
  • @NilsWasell No problem, happy to help. Happy coding! – Craig Otis Sep 19 '14 at 11:57