1

I try to create my first project with swift 3.

I try to get data from my API. This works pretty good if I manually start the function. I need to synchronize the async request.

I need to trigger my function 3 times and wait for the others to complete.

makeGetCall(URLstring: "api1")

wait to complete

makeGetCall(URLstring: "api2")

wait to complete

makeGetCall(URLstring: "api3") 

Set this to background and trigger every 5 seconds.

func makeGetCall(URLstring: String, update: Bool) {

    let completeURL = "http://myapi/" + URLstring


    // Set up the URL request
    guard let url = URL(string: completeURL) else {
        print("Error: cannot create URL")
        return
    }
    let urlRequest = URLRequest(url: url)

    // set up the session
    let config = URLSessionConfiguration.default
    let session = URLSession(configuration: config)

    // make the request
    let task = session.dataTask(with: urlRequest) {
        (data, response, error) in
        // check for any errors
        guard error == nil else {
            print("error calling GET on /todos/1")
            print(error as Any)
            return
        }
        // make sure we got data
        guard let responseData = data else {
            print("Error: did not receive data")
            return
        }

            // parse the result as XML
        if URLstring == "devicelist.cgi" {
            self.readDevice(XMLData: responseData)
        }

        if URLstring == "statelist.cgi" {
            self.readDeviceData(XMLData: responseData, update: update)
        }

        if URLstring == "functionlist.cgi" {
            self.readGewerke(XMLData: responseData)
        }
    }

    task.resume()

}

Can somebody help please.

Hagen

This is what I tried with completion handler:

    override func viewDidLoad() {
    super.viewDidLoad()

    makeGetCall(input: "statelist.cgi") {
        (result: Bool) in
        print("finished statelist")

    }
    makeGetCall(input: "devicelist.cgi") {
        (result: Bool) in
        print("finished devicelist")
    }


    makeGetCall(input: "functionlist.cgi") {
        (result: Bool) in
        print("finished functionlist")
    }

}

func makeGetCall(input: String, completion: @escaping (_ result: Bool) -> Void) {



    let completeURL = "http://192.168.0.25/addons/xmlapi/" + input


    // Set up the URL request
    guard let url = URL(string: completeURL) else {
        print("Error: cannot create URL")
        return
    }
    let urlRequest = URLRequest(url: url)

    // set up the session
    let config = URLSessionConfiguration.default
    let session = URLSession(configuration: config)

    // make the request
    let task = session.dataTask(with: urlRequest) {
        (data, response, error) in
        // check for any errors
        guard error == nil else {
            print("error calling GET on /todos/1")
            print(error as Any)
            return
        }
        // make sure we got data
        guard data != nil else {
            print("Error: did not receive data")
            return
        }
         completion(true)

    }

    task.resume()


}

If I put the 3 calls together it worked as it should. I thing it should also work with GCD but most of examples for swift 2.

    makeGetCall(input: "devicelist.cgi") {
        (result: Bool) in
        print("finished devicelist")
        self.makeGetCall(input: "functionlist.cgi") {
            (result: Bool) in
            print("finished functionlist")
           self.makeGetCall(input: "statelist.cgi") {
                (result: Bool) in
                print("finished statelist")

            }
        }
    }

Maybe now somebody can help.

Thanks Hagen

4
  • Add a completion handler to makeGetCall() and use a DispatchGroup to wait or get notified. Commented Feb 9, 2017 at 20:38
  • I tried to solve my problem but didn't´t get working. Can somebody give me advice. Commented Feb 10, 2017 at 15:41
  • Show what you have tried with completion handler Commented Feb 11, 2017 at 16:43
  • Please see above I edited my question. Commented Feb 13, 2017 at 16:51

1 Answer 1

1

Use a DispatchGroup to get notified when something happens.

override func viewDidLoad() {
    super.viewDidLoad()

    let stateListGroup = DispatchGroup()

    stateListGroup.enter()
    makeGetCall(input: "statelist.cgi") {
        (result: Bool) in
        print("finished statelist")
        stateListGroup.leave()
    }

    let deviceListGroup = DispatchGroup()
    deviceListGroup.enter()

    // the notify closure is called when the (stateList-) groups enter and leave counts are balanced.
    stateListGroup.notify(queue: DispatchQueue.main)  {
        self.makeGetCall(input: "devicelist.cgi") {
            (result: Bool) in
            print("finished devicelist")
            deviceListGroup.leave()
        }
    }

    let functionListGroup = DispatchGroup()
    functionListGroup.enter()

    deviceListGroup.notify(queue: DispatchQueue.main)  {
        self.makeGetCall(input: "functionList") {
            (result: Bool) in
            print("finished functionlist")
            functionListGroup.leave()
        }
    }

    functionListGroup.notify(queue: DispatchQueue.main)  {
        print("update ui here")
    }
}

Prints:

statelist.cgi
finished statelist
devicelist.cgi
finished devicelist
functionList
finished functionlist
update ui here

Also keep in mind that the completion handler of session.dataTask() is called on a background queue, so I recommend to dispatch completion(true) on the main queue to avoid unexpected behaviour:

DispatchQueue.main.async {
    completion(true)
}
Sign up to request clarification or add additional context in comments.

2 Comments

Thanks a lot shallowThought. I modified it to group.notify(queue: DispatchQueue.main) and now it work as it should.
Oh, sorry. Written in the subway ... Fixed that in answer update. Here at SO we thank by up-voting/accepting the answer btw.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.