Using PromiseKit to force sequential download

僤鯓⒐⒋嵵緔 提交于 2019-12-06 00:16:02

问题


I am using PromiseKit and would like to force sequential download of JSONs. The count of JSONs might change.

I have read this about chaining. If I had a fixed number of say 3 downloads, this would be fine.

But what if I had a changing count of download that I would like to download sequentially?

This is my code for 2 URLs. I wonder how I could do this with dateUrlArray[i] iteration over the array?

 - (void)downloadJSONWithPromiseKitDateArray:(NSMutableArray *)dateUrlArray {
    [self.operationManager GET:dateUrlArray[0]
                    parameters:nil]
    .then(^(id responseObject, AFHTTPRequestOperation *operation) {
        NSDictionary *resultDictionary = (NSDictionary *) responseObject;
        Menu *menu = [JsonMapper mapMenuFromDictionary:resultDictionary];
        if (menu) {
            [[DataAccess instance] addMenuToRealm:menu];
        }
        return [self.operationManager GET:dateUrlArray[1]
                               parameters:nil];
    }).then(^(id responseObject, AFHTTPRequestOperation *operation) {
        NSDictionary *resultDictionary = (NSDictionary *) responseObject;

        Menu *menu = [JsonMapper mapMenuFromDictionary:resultDictionary];
        if (menu) {
            [[DataAccess instance] addMenuToRealm:menu];
        }
    })
    .catch(^(NSError *error) {
        dispatch_async(dispatch_get_main_queue(), ^{
            [self handleCatchwithError:error];
        });
    }).finally(^{
        dispatch_async(dispatch_get_main_queue(), ^{
            DDLogInfo(@".....finally");
        });
    });
}

回答1:


The concept you're looking for is thenable chaining. You want to chain multiple promises in a for loop.

My Objective-C is really rusty - but it should look something like:

// create an array for the results
__block NSMutableArray *results = [NSMutableArray arrayWithCapacity:[urls count]];
// create an initial promise
PMKPromise *p = [PMKPromise promiseWithValue: nil]; // create empty promise
for (id url in urls) {
    // chain
    p = p.then(^{
        // chain the request and storate
        return [self.operationManager GET:url
                parameters:nil].then(^(id responseObject, AFHTTPRequestOperation *operation) {
              [results addObject:responseObject]; // reference to result
              return nil; 
        });
    });
}
p.then(^{
    // all results available here
});



回答2:


For those of us looking for a Swift 2.3 solution:

import PromiseKit

extension Promise {
    static func resolveSequentially(promiseFns: [()->Promise<T>]) -> Promise<T>? {
        return promiseFns.reduce(nil) { (fn1: Promise<T>?, fn2: (()->Promise<T>)?) -> Promise<T>? in
            return fn1?.then({ (_) -> Promise<T> in
                return fn2!()
            }) ?? fn2!()
        }
    }
}

Note that this function returns nil if the promises array is empty.

Example of use

Below is an example of how to upload an array of attachments in sequence:

func uploadAttachments(attachments: [Attachment]) -> Promise<Void> {
    let promiseFns = attachments.map({ (attachment: Attachment) -> (()->Promise<Void>) in
        return {
            return self.uploadAttachment(attachment)
        }
    })
    return Promise.resolveSequentially(promiseFns)?.then({}) ?? Promise()
}

func uploadAttachment(attachment: Attachment) -> Promise<Void> {
    // Do the actual uploading
    return Promise()
}



回答3:


Thanks for Vegard's answer and I rewrite for Swift 3:

extension Promise {
    static func resolveSequentially(promiseFns: [()->Promise<T>]) -> Promise<T>? {
        return promiseFns.reduce(nil) { (fn1: Promise<T>?, fn2: (()->Promise<T>)?) -> Promise<T>? in
            return fn1?.then{ (_) -> Promise<T> in
                return fn2!()
            } ?? fn2!()
        }
    }
}



/* Example */
func uploadAttachments(_ attachments: [Attachment]) -> Promise<Void> {
    let promiseFns = attachments.map({ (attachment: Attachment) -> (()->Promise<Void>) in
        return {
            return self. uploadAttachment(attachment)
        }
    })

    return Promise.resolveSequentially(promiseFns: promiseFns)?.then{Void -> Void in} ?? Promise { Void -> Void in }
}


来源:https://stackoverflow.com/questions/30692132/using-promisekit-to-force-sequential-download

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!