user3171597
user3171597

Reputation: 457

Swift JSON data on TableView lags

I have an issue with my TableView displaying JSON data. When it is displayed, it currently lags whenever I scroll up and down. I know that I have to use the Grand Central Dispatch methods (GCD) for that, however, I have no clue on how to go about that.

This is my code snippet in my viewDidLoad() method that just grabs the JSON data into a dictionary:

// Convert URL to NSURL
    let url = NSURL(string: apiURL)

    let jsonData: NSData?

    do {
        /*
        Try getting the JSON data from the URL and map it into virtual memory, if possible and safe.
        DataReadingMappedIfSafe indicates that the file should be mapped into virtual memory, if possible and safe.
        */
        jsonData = try NSData(contentsOfURL: url!, options: NSDataReadingOptions.DataReadingMappedIfSafe)
    } catch let error as NSError
    {
        showErrorMessage("Error in retrieving JSON data: \(error.localizedDescription)")
        return
    }

    if let jsonDataFromApiURL = jsonData
    {
        // The JSON data is successfully obtained from the API

        /*
        NSJSONSerialization class is used to convert JSON and Foundation objects (e.g., NSDictionary) into each other.
        NSJSONSerialization class's method JSONObjectWithData returns an NSDictionary object from the given JSON data.
        */

        do
        {
            let jsonDataDictionary = try NSJSONSerialization.JSONObjectWithData(jsonDataFromApiURL, options: NSJSONReadingOptions.MutableContainers) as? NSDictionary

            // Typecast the returned NSDictionary as Dictionary<String, AnyObject>
            dictionaryOfRecipes = jsonDataDictionary as! Dictionary<String, AnyObject>

            // Grabs all of the matched recipes
            // This will return an array of all of the matched recipes
            matchedRecipes = dictionaryOfRecipes["matches"] as! Array<AnyObject>

            // Returns the first 10 recipes shown in the JSON data
            recipeCount = matchedRecipes.count

        }catch let error as NSError
        {
            showErrorMessage("Error in retrieving JSON data: \(error.localizedDescription)")
            return
        }
    }

    else
    {
        showErrorMessage("Error in retrieving JSON data!")
    }

Thanks!

Upvotes: 0

Views: 299

Answers (2)

user3171597
user3171597

Reputation: 457

I've figured it out. It wasn't just the

dispatch_async(dispatch_get_main_queue())

because that is just using the main thread, and you should only use that when you are displaying JSON information onto a view. If I am understanding this correctly, you are supposed to use:

 dispatch_async(dispatch_get_global_queue(QOS_CLASS_USER_INITIATED, 0)){}

Whenever you are trying to download the data, such as an image, before displaying it onto a view. Here is an example code for anyone interested:

    //-----------------
    // Set Recipe Image
    //-----------------
    dispatch_async(dispatch_get_global_queue(QOS_CLASS_USER_INITIATED, 0))
    {
        // This grabs the Image URL from JSON
        let imageURL = recipeDataDict["imageUrlsBySize"] as! NSDictionary
        let imageSize90 = imageURL["90"] as! String

        // Create an NSURL from the given URL
        let url = NSURL(string: imageSize90)

        var imageData: NSData?

        do {
            /*
            Try getting the thumbnail image data from the URL and map it into virtual memory, if possible and safe.
            DataReadingMappedIfSafe indicates that the file should be mapped into virtual memory, if possible and safe.
            */
            imageData = try NSData(contentsOfURL: url!, options: NSDataReadingOptions.DataReadingMappedIfSafe)
        } catch let error as NSError
        {
            self.showErrorMessage("Error in retrieving thumbnail image data: \(error.localizedDescription)")
        }
        dispatch_async(dispatch_get_main_queue(),
        {
            if let image = imageData
            {
                // Image was successfully gotten
                cell.recipeImage!.image = UIImage(data: image)
            }
            else
            {
                self.showErrorMessage("Error occurred while retrieving recipe image data!")
            }
        })
    }

Before I had just the dispatch_get_global_queue WITHOUT the main_queue thread, the images would download very slowly (but the tableview did not lag). However, once I added in the main_queue before displaying the JSON data, it was downloaded instantly (or almost instantly) and without any further lags.

More information on: https://tetontech.wordpress.com/2014/06/04/swift-ios-and-grand-central-dispatch/

Upvotes: 0

Mohammed Janish
Mohammed Janish

Reputation: 207

Give your code inside

dispatch_async(dispatch_get_main_queue(), {
// Your Execution Code
}

This simply works

Upvotes: 1

Related Questions