manohjay
manohjay

Reputation: 110

unexpectedly found nil while unwrapping optional value, but there is some value

I am trying to get do a GET request, and save the following results from into NSMutuableArray. Then I am trying to load the following data I got into a tableview, but I am getting an "unexpectedly found nil while unwrapping optional value" whenever I try to configure the number of rows.

var dataArray:NSMutableArray?

Alamofire.request(.GET, "SOMERANDOMWEBSITE") .responseJSON { response in
        // using if-let syntax to save json into our NSMutuableArray
        if let JSON = response.result.value {
            self.dataArray = JSON as? NSMutableArray
        }
    }

When i try to configure the number of rows:

    override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    // #warning Incomplete implementation, return the number of rows

    return self.dataArray.count
}

It gives me an error: "unexpectedly found nil while unwrapping optional value". But what's strange is that when I create a random button to see if the .count is indeed nil:

    @IBAction func function(sender: AnyObject) {
    print(self.dataArray?.count)
}

it returns me with Optional(2) instead of nil. Any ideas?

Upvotes: 0

Views: 400

Answers (2)

Eric Aya
Eric Aya

Reputation: 70097

You made your array an Optional. We can see that here:

print(self.dataArray?.count)

So until it's populated in Alamofire's closure (the network request happens in the background), it is nil.

You quote:

return self.dataArray.count

but actually you probably have done

return self.dataArray!.count

This is why it crashes.

So you have to declare another option for count for when it's nil. A solution could be to safely unwrap the array then return the count or return a default value:

if let array = self.dataArray {
    return array.count
}
return 0

This same logic can be expressed in a single line, as @brian-nickel notes in the comments:

return self.dataArray?.count ?? 0

Also, as stated by @vadian in the comments, absolutely, an Optional array makes little sense here, it would be better to just have a non-optional empty array from the beginning.

Upvotes: 3

vadian
vadian

Reputation: 285069

It's not strange, it's asynchronous.

Initially you declare dataArray as optional (aka nil) but don't initialize it.

The first attempt to update the table view fails (crashes) because calling count on nil is a bad idea.

Meanwhile the asynchronous request method returns the data and assigns it to dataArray which has now an (optional) value.

That's why you get a result in function.

Solution is to declare and initialize the array as non-optional Swift type.

var dataArray = [AnyObject]()

Probably there is a more specific type than AnyObject

and assign the returned data accordingly casting the result to the "better" type.


Basically declaring table view data source arrays as optional is absurd since your table view is always non-optional.

Upvotes: 1

Related Questions