Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Alamofire multiple requests iteration

I have four different requests in my application, three of them requires one call only and the last requires from 1 - 10.

All works fine until the last request when I´m iterating through my data and making the calls. This is my code in Class1:

var data = ...
var points = ...

// I create a new group
let getPointGroup = dispatch_group_create()

// I iterate through my data
for d in data{
    // I enter the group
    dispatch_group_enter(getPointGroup)
    dataService.getPoints(d.point), success: { points -> Void in
        points.append(points)

        // I leave the group so that I go to the next iteration
        dispatch_group_leave(getPointGroup)
    }
}

Alamofire request looks like this in Class2:

let headers = [
    "Authorization": "Bearer \(token)",
    "Content-Type": "application/x-www-form-urlencoded"
]

Alamofire.request(.GET, url, headers:headers)
    .responseJSON { response in
        switch response.result {
        case .Success:
            let json = JSON(data: response.data!)
            print(json)
            success(json)
        case .Failure(let error):
            print(error)
        }
}

But I never hit the GET request, if I remove the iteration completely and just call the Alamofire request once it works perfectly.

Any ideas of how to solve the Alamofire iteration request?

Edit
Not really a duplicate, I have the snippets below in the different classes and the example does not really solve my issue

like image 840
user5855868 Avatar asked Jan 01 '26 15:01

user5855868


1 Answers

If this is not running, you could be deadlocking if you use dispatch_group_wait on the main thread, thereby blocking that thread, and preventing Alamofire from running any of its completion handlers (which also require the main thread). This is solved (assuming you are, indeed, using dispatch_group_wait), by replacing that with dispatch_group_notify.

Thus:

let group = dispatch_group_create()

for d in data {
    // I enter the group
    dispatch_group_enter(group)
    dataService.getPoints(d.point)) { additionalPoints, error in
        defer { dispatch_group_leave(group) }

        guard let let additionalPoints = additionalPoints else {
            print(error)
            return
        }

        points.append(additionalPoints)
    }
}

dispatch_group_notify(group, dispatch_get_main_queue()) {
    // go to the next iteration here
}

Where:

func getPoints(point: WhateverThisIs, completionHandler: (JSON?, NSError?) -> ()) {
    let headers = [
        "Authorization": "Bearer \(token)"
    ]

    Alamofire.request(.GET, url, headers: headers)
        .responseJSON { response in
            switch response.result {
            case .Success:
                let json = JSON(data: response.data!)
                completionHandler(json, nil)
            case .Failure(let error):
                completionHandler(nil, error)
            }
    }
}

Now, I don't know what your various parameter types were, so I was left to guess, so don't get lost in that. But the key is that (a) you should make sure that all paths within your Alamofire method will call the completion handler; and (b) the caller should use dispatch_group_notify rather than dispatch_group_wait, avoiding the blocking of any threads.

Note, in order to make the completion handler callable even if the network request failed, I had to make the parameter to that closure optional. And while I was there, I added an optional error parameter, too.


A few unrelated changes included in the above sample:

  1. I'd suggest using a different variable name for the parameter of your closure. The points.append(points) in your original code snippet suggests some confusion between your points array and the points that is passed back in the closure.

  2. You don't have to set the Content-Type header, as Alamofire does that for you.

  3. I didn't change it above, but it is inefficient to use responseJSON (which uses NSJSONSerialization to parse the JSON) and then use SwiftyJSON to parse the raw data with NSJSONSerialization again. Personally, I don't bother with SwiftyJSON, but if you want to use it, I'd suggest use Alamofire's response method rather responseJSON. There's no point in parsing the JSON twice.

like image 115
Rob Avatar answered Jan 03 '26 12:01

Rob



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!