catcatcat
catcatcat

Reputation: 377

Swift 3 - Function Inside DispatchQueue

I called a function inside DispatchQueue.main.async. Here's my code:

let group = DispatchGroup()
group.enter()

DispatchQueue.main.async {
        for i in 0 ... (Global.selectedIcons.count - 1) {
            if self.albumorphoto == 1 {
                if i == 0 {
                    self.detector = 1
                    self.uploadPhoto() //here
                }
                else {
                    self.detector = 2
                    self.uploadPhoto() //here
                }
            }
            else {
                self.uploadPhoto() //here
            }
        }
        group.leave()
    }

    group.notify(queue: .main) {
        print("done")
    }
}

func uploadPhoto(){
    var request = URLRequest(url: URL(string: url)!)
    request.httpMethod = "POST"
    request.setValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type")

    let params = param

    request.httpBody = params.data(using: String.Encoding.utf8)

    let task = URLSession.shared.dataTask(with: request) { data, response, error in
        guard let data = data, error == nil else {
            print("error=\(error!)")
            return
        }

        if let httpStatus = response as? HTTPURLResponse, httpStatus.statusCode != 200 {
            print("statusCode should be 200, but is \(httpStatus.statusCode)")
            print("response = \(response!)")
        }

        let responseString = String(data: data, encoding: .utf8)
        print("responseString = \(responseString!)")

        if self.detector == 1 {
            self.album = self.parseJsonData(data: data)
        }

    }

    task.resume()
}

func parseJsonData(data: Data) -> [AnyObject] {
    do {
        let jsonResult = try JSONSerialization.jsonObject(with: data, options: JSONSerialization.ReadingOptions.mutableContainers) as? NSDictionary
        let jsonalbum = jsonResult!["data"] as? [AnyObject]
        for jsonAlbum in jsonalbum! {
            self.folderID = jsonAlbum["id"] as! String
        }
    } catch {
        print(error)
    }

    return album
}

I wish to make it wait until all the tasks in DispathcQueue finish. It works but the problem is my function uploadPhoto(). It can't wait until uploadPhoto() finish doing its task. Any idea to solve this? Thanks!

Upvotes: 1

Views: 764

Answers (1)

mxgzf
mxgzf

Reputation: 946

Using a DispatchGroup is the right choice here, but you have to enter and leave for each asynchronous task:

let group = DispatchGroup()
photos.forEach { photo in

    group.enter()
    // create the request for the photo

    URLSession.shared.dataTask(with: request) { data, response, error in

        group.leave()
        // handle the response

    }.resume()
}
group.notify(queue: .main) {
    print("All photos uploaded.")
}

You don't need a DispatchQueue.async() call because URLSession.shared.dataTask is already asynchronous.

In my code i assumed that you want to model your objects as Photo and replace Global.selectedIcons.count with a photos array:

class Photo {
    let isAlbum: Bool
    let isDefector: Bool
    let imageData: Data
}

I'd recommend you take a look at Alamofire and SwiftyJSON to further improve your code. These are popular libraries that make dealing with network requests a lot easier. With them you can reduce almost the entire uploadPhoto()/parseJsonData() functions to something like this:

Alamofire.upload(photo.imageData, to: url).responseSwiftyJSON { json in
    json["data"].array?.compactMap{ $0["id"].string }.forEach {
        self.folderID = $0
    }
}

This makes your code more stable because it removes all forced unwrapping. Alamofire also provides you with features like upload progress and resuming & cancelling of requests.

Upvotes: 2

Related Questions