coopwatts coopwatts - 1 month ago 8
Swift Question

Unexpectedly found nil when unwrapping optional value - NSMutableArray - Swift

I am retrieving posts in a data handler from a DB for a news feed and I run a php script and echo the JSON encoded data back to my application, at which point the data is parsed and stored in a model of a "post", there is a protocol that is used in the view controller to get the data once it has been downloaded. My problem is that I am getting the notorious "Unexpectedly found nil when unwrapping optional value" error when I pass the NSMutableArray of "post" objects to the function "itemsDownloaded" which is function of the protocol. I checked all the values being parsed and they exist, and I also checked the count of the array to make sure it has values. The exception is occurring on the line

self.delegate.itemsDownloaded(posts)


The code to handle the data is this :

import Foundation

protocol PostDataHandlerProtocol: class {
func itemsDownloaded(items: NSArray)
}


class PostDataHandler: NSObject, NSURLSessionDataDelegate {

weak var delegate: PostDataHandlerProtocol!

var data : NSMutableData = NSMutableData()

//The path to the php script to be executed
let urlPath: String = "www.something.com/myphpscript.php"

func downloadItems() {

let url: NSURL = NSURL(string: urlPath)!
var session: NSURLSession!
let configuration = NSURLSessionConfiguration.defaultSessionConfiguration()


session = NSURLSession(configuration: configuration, delegate: self, delegateQueue: nil)

let task = session.dataTaskWithURL(url)

task.resume()

}

func URLSession(session: NSURLSession, dataTask: NSURLSessionDataTask, didReceiveData data: NSData) {
self.data.appendData(data);

}

func URLSession(session: NSURLSession, task: NSURLSessionTask, didCompleteWithError error: NSError?) {
if error != nil {
print("Failed to download data")
}else {
print("Data downloaded")
self.parseJSON()
}

}

func parseJSON() {

var jsonResult: NSMutableArray = NSMutableArray()

do{
jsonResult = try NSJSONSerialization.JSONObjectWithData(self.data, options:NSJSONReadingOptions.AllowFragments) as! NSMutableArray

} catch let error as NSError {
print(error)

}

var jsonElement: NSDictionary = NSDictionary()
let posts: NSMutableArray = NSMutableArray()

for(var i = 0; i < jsonResult.count; i++)
{

jsonElement = jsonResult[i] as! NSDictionary

let post = PostModel()

//The following insures none of the JsonElement values are nil through optional binding
let username = jsonElement["username"] as? String
let imagePath = jsonElement["user_imagePath"] as? String
let postID = (jsonElement["post_id"] as! NSString).integerValue
let postRep = (jsonElement["post_rep"] as! NSString).integerValue
let postType = jsonElement["post_type"] as? String
let postDate = jsonElement["post_date"] as? String
let comment = jsonElement["comment"] as? String


post.username = username
post.imagePath = imagePath
post.postID = postID
post.postRep = postRep
post.postType = postType
post.postDate = postDate
post.comment = comment

posts.addObject(post)
}

dispatch_async(dispatch_get_main_queue(), { () -> Void in

self.delegate.itemsDownloaded(posts)

})
}

}


In my view controller, I create a new data handler
let postHandler = PostDataHandler()
and then once the view has loaded I call
postHandler.downloadItems()
and in the view controller declaration I conformed to the protocol and implemented itemsDownloaded:

func itemsDownloaded(items: NSArray) {
allPosts = items as! [PostModel]
indicator.stopAnimating()
self.tableVIew.reloadData()
}


Does anyone know why this is happening? I tried to look at the numerous postings regarding this error as I'm aware it's quite common, but couldn't find anything that helped me. Many of the postings say there should be a check to ensure it's not nil, the problem is I didn't think NSMutableArray can be optional, and also I checked all the values and they don't appear to be nil, so those answers did not help me. In the thread exceptions it says something related to a closure, which I think could be causing the issue, I'm just not exactly sure what or how.

Answer

None of the code that you showed ever set your PostDataHandler's delegate property to anything, so it is reasonable to suppose that it is still nil, which perfectly explains why you crash at runtime when you try to access it as if it were an actual object.