Static method to parse remote JSON data

Hello,

I am trying to parse JSON data from github using a static function and therefore need my getRemoteFabricData function to return the parsed data. I know how to do this with local data but I can’t seem to get the data out of my session.dataTask object. My fabricData variable is marked as out of scope.

Any help would be appreciated, thanks!

static func getRemoteFabricData() -> [Fabric] {
                
        // String path
        let urlString = "https://asilena.github.io/ADCData/fabricData.json"
        
        // Create url object
        let url = URL(string: urlString)
        
        guard url != nil else {
            // Couldn't create url
            return []
        }
        
        // Create a url request object
        let request = URLRequest(url: url!)
        
        // Get the session and kick off the task
        let session = URLSession.shared
        
        
        let dataTask = session.dataTask(with: request) { data, response, error in
            
            // Check if there is an error
            guard error == nil else {
                //There was an error
                return
            }
            
            // Create json decoder
            let decoder = JSONDecoder()
            
            do{
                // Decode
                let fabricData = try decoder.decode([Fabric].self, from: data!)
                
                // Add the unique IDs
                for f in fabricData {
                    f.id = UUID()
                }
            }
            catch {
                // Error with parsing JSON
                print(error)
            }
        }
        
        // Kick off the data task
        dataTask.resume()
        
        return fabricData
    }

Declare your fabricData variable as an array of [Fabric] before the dataTask. ie:

var fabricData: [Fabric] = []

Then in your do { }, rather than

let fabricData = try decoder.decode([Fabric].self, from: data!)

use

fabricData = try decoder.decode([Fabric].self, from: data!)
1 Like

Hi, that helped thank you!

The function is returning an empty array though. It looks like the dataTask takes too long and the return command is executed before it has the chance to populate the fabricData array.

Would forcing the function to wait for the array to be populated before returning the fabricData array work or would I need to use pointers?

Thanks for the help

@Asile

Hi Elisa,

The dataTask is performed on a background thread so yes, the return command is more than likely being executed before the dataTask has finished. Is this code in your ObservableObject class?

Hi @Asile , using data task may take longer, so you may use the async/await feature and use the concurrency APIs available for URLSession.

static func getRemoteFabricData() async -> [Fabric] {
        
        // String path
        let urlString = "https://asilena.github.io/ADCData/fabricData.json"
        
        // Create url object
        let url = URL(string: urlString)
        
        guard url != nil else {
            // Couldn't create url
            return []
        }
        
        // Create a url request object
        let request = URLRequest(url: url!)
        
        // Get the session and kick off the task
        let session = URLSession.shared
        
        do{
            let (data, _) = try await session.data(for: request)
            let decoder = JSONDecoder()
            // Decode
            let fabricData = try decoder.decode([Fabric].self, from: data!)
            
            // Add the unique IDs
            for f in fabricData {
                f.id = UUID()
            }
            
            return fabricData
        }
        catch {
            // Error with parsing JSON
            print(error)
        }
    }

If you want to learn more about async/await feature, you can watch this video from iOS Academy