2015-06-07 14 views
5

Sto utilizzando PromiseKit e vorrei forzare il download sequenziale di JSON. Il conteggio dei JSON potrebbe cambiare.Utilizzo di PromiseKit per forzare il download sequenziale

Ho letto this sul concatenamento. Se avessi un numero fisso di download di dire 3, questo andrebbe bene.

Ma cosa succede se ho un conteggio variabile del download che vorrei scaricare sequenzialmente?

Questo è il mio codice per 2 URL. Mi chiedo come potrei farlo con l'iterazione dateUrlArray[i] sull'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"); 
     }); 
    }); 
} 

risposta

4

Il concetto che stai cercando è then concatenamento grado. Vuoi mettere in catena più promesse in un ciclo for.

mio Objective-C è davvero arrugginita - ma dovrebbe essere simile:

// 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 
}); 
+0

Molte molte grazie per ObjC 'arrugginito' ;-) Ottima risposta, e IMHO un'omissione sul sito Promisekit. Ho fatto una piccola modifica (p dovrebbe essere di tipo PMKPromise). – brainray

3

Per quelli di noi che cercano un Swift 2.3 soluzione:

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!() 
     } 
    } 
} 

Si noti che questa funzione restituisce nil se l'array promises è vuoto.

Esempio di utilizzo

seguito è un esempio di come caricare un array di allegati in sequenza:

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() 
} 
+0

Grazie mille per l'input! BTW: nel frattempo risolvo questo tipo di compiti con NSOperation wgich che non richiede una libreria di terze parti – brainray

+0

Grazie per il feedback, questo ha assolutamente senso! – Vegard

2

Grazie per la risposta di Vegard e riscrivere per 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 } 
} 
Problemi correlati