Alamofire - 如何处理完成块?

时间:2016-08-31 10:46:57

标签: ios swift alamofire

我在iOS中很新,想要和使用Alamofire。我想问下面的内容:如果已经处理了所有项目(在我的情况下是用户),如何调用一些完成块。完成块处于延迟块

StopsHandler.swift

func requestStopsForUser(user: User, completion: (result: RequestResult, json: JSON?) -> Void) {
    alamofireManager?.request(.GET, "\(AppSettings.ApiURL)/v1/users/\(user.id)/stops.json", headers: ["Authorization": "Token token=\(user.apiKey)"]).responseJSON { response in
        switch response.result {
        case .Success:
            if let value = response.result.value {
                completion(result: .Success, json: JSON(value))
            }
        case .Failure(let error):
            if error.code == NSURLErrorTimedOut {
                completion(result: .TimedOut, json: nil)
            } else {
                completion(result: .ConnectionFailed, json: nil)
            }
        }
    }
}

Main.swift

func fetchUsersAndStops(completion: (result: RequestResult) -> Void ) {

    var allStopsToWrite = [[Stop]]() //for each user we have array of stops to write in model

    requestAllUsers() { result, json in
        switch result {
        case .Success:
            let users = self.usersFromJSON(json)

            for (i, user) in users.enumerate() {   
                StopsHandler.sharedInstance.requestStopsForUser(user) { result, json in
                    print("i in = \(i)")
                    switch result {
                    case .Success:
                        defer {
                            let isLastUser = (i == users.count - 1)
                            if isLastUser {
                                try! self.realm.write(transactionBlock: {
                                    for (index, stopsToWrite) in allStopsToWrite.enumerate() {
                                        users[index].stops.appendContentsOf(stopsToWrite)
                                        self.realm.add(users[index], update: true)
                                    }},
                                    completion: {
                                        completion(result: .Success) //I want to call this completion when last user is already handled.
                                })
                            }
                        }

                        guard let json = json else {return}
                        let stops = StopsHandler.sharedInstance.stopsFromJSON(json)

                        let globalStops = self.realm.objects(Stop)

                        var stopsToWrite = [Stop]()

                        for stop in stops {
                            if globalStops.filter("id = '\(stop.id)'").first == nil {
                                stopsToWrite.append(stop)
                                if let currentUserId = self.currentUser?.id {
                                    if currentUserId == user.id {
                                        user.loggedIn = true
                                    }
                                }
                            }
                        }
                        allStopsToWrite.append(stopsToWrite)
                    case .TimedOut:
                        completion(result: .TimedOut)
                    case .ConnectionFailed:
                        completion(result: .ConnectionFailed)
                    }
                }
            }
        case .TimedOut:
            completion(result: .TimedOut)
        case .ConnectionFailed:
            completion(result: .ConnectionFailed)
        }
    }
}

我假设我的代码在main_queue中运行,我希望输出如下(我在服务器上有4个用户):

i in = 0
i in = 1
i in = 2
i in = 3

但我突然有了以下内容:

i in = 3
i in = 1
i in = 2
i in = 0

我不知道为什么。任何帮助都非常感谢!提前谢谢!

2 个答案:

答案 0 :(得分:0)

asynchronously未在主队列上运行。它运行.responseJSON,但默认情况下main queue将在dispatch_after(dispatch_time(DISPATCH_TIME_NOW, Int64(Double(0.2) * Double(NSEC_PER_SEC))), dispatch_get_main_queue(), { // your code here. }) 上返回,以允许您更新UI。因此,您的输出不是您所期望的。

如果您希望它按顺序返回,则必须将请求包装在调度主队列中。

这样的事情:

@interface ViewController : UIViewController
{
    CLLocationManager *locationManager;
}
@end

@implementation ViewController

- (void)viewDidLoad
{
    [super viewDidLoad];

    CLLocationManager *locationManager = [[CLLocationManager alloc] init];
    [locationManager startUpdatingLocation];
}

答案 1 :(得分:0)

由于Alarmofire在异步方法中调用请求。这就是为什么所有请求都是一次调用的原因,但响应时间对于所有请求都不一样。

要按顺序呼叫所有请求,您可以在上一次服务完成后致电服务。

由于我们遇到同样的问题所以我们确实使用了dispatch_block_t来执行序列任务。

MongoClient.connect(mongoUrl, (err, db) => {
  assert.equal(null,err);
  var collection_data = db.collection('threadContents').find();
  collection_data.on('data', (doc) => {
    var msg = doc.messages;
    for (var variable in msg) {
      console.log(msg);
    }//forin(msg)
  });//collection_data.on
});//mongo.connect

注意:这仅在您使用不同的呼叫获取每个用户信息时才有用。如果您在单个调用中获得所有用户信息,那么您只需要使用NSSortDescriptor对用户进行排序。

如果您遇到与执行序列任务相关的任何问题,可以在下面留言。