10

Due mesi fa ho iniziato a scrivere una nuova applicazione iPhone e per questo motivo ho creato un servizio web RESTFul generico, che mi consente di avere molte di queste funzionalità necessarie come l'autenticazione dell'utente, i profili utente, un sistema di amicizia, elaborazione dei media, un sistema di messaggistica e così via. Nella mia mente ci sono diversi casi d'uso per riutilizzare questo servizio web per le future applicazioni iPhone.iOS App Architecture con NSOperations

Con questo stato d'animo, ho deciso di scrivere una libreria statica per questa applicazione (e tutte le future app) che gestisce tutte le operazioni di installazione e elaborazione dei media (immagine, video, audio), comunicando con il servizio web , analisi e mappatura dei risultati, gestione di CoreData e così via.

Data la mia applicazione ci sono scenari in cui sono in esecuzione molte attività parallele (caso peggiore) ad es. l'utente modifica attualmente la propria immagine del profilo, mentre l'applicazione invia la posizione degli utenti al server (in background) e viene ricevuta una nuova notifica push.

Così deciso di incapsulare ogni operazione logica (come SendUserLocation o GetCurrentFriendList) in un NSOperation e aggiungerli a un servizioQueue (NSOperationQueue).

Ogni operazione è in grado di generare sottogruppi quando l'operazione ha ottenuto un risultato dal servizio web e deve elaborarlo ora.

alt text

Un tipico metodo ServiceManager sembra

- (void)activateFriendsSync:(id)observer onSuccess:(SEL)selector { 
    ELOSyncFriends *opSyncFriends = [[ELOSyncFriends alloc] initWithSM:self]; 
    [self ELServiceLogger:opSyncFriends]; 
    [serviceQueue addOperation:opSyncFriends]; 
    if(observer) { 
     [self registerObserver:observer selector:selector name:opSyncFriends.notificationName]; 
    } 
} 

Ogni operazione, richiesta (per server) e Subtask utilizza un GUID come notificationName per notificare l'oggetto padre quando è fatto di elaborazione. Se tutto è in un'operazione, invia una notifica all'interfaccia utente.

Detto questo, il codice per l'aggiunta e la rimozione di sottocompiti assomiglia a questo

- (void)removeSubTask:(NSNotification*)notification { 
    ELRequest *request = (ELRequest*)[notification object]; 
    [subTasks removeObjectIdenticalTo:request.notificationName]; 
    if([subTasks count] == 0) { 
     // all SubTaks done, send notification to parent 
     [serviceManager.notificationCenter postNotificationName:self.notificationName object:request]; 
    } 
} 

- (NSString*)addSubTask { 
    NSString* newName = [self GetUUID]; 
    [subTasks addObject:[newName retain]]; 
    [serviceManager.notificationCenter addObserver:self selector:@selector(removeSubTask:) name:newName object:nil]; 
    return newName; 
} 

- (NSString *)GetUUID { 
    CFUUIDRef theUUID = CFUUIDCreate(NULL); 
    CFStringRef string = CFUUIDCreateString(NULL, theUUID); 
    CFRelease(theUUID); 
    return [(NSString *)string autorelease]; 
} 

Ora tutto quello che ho da fare è chiamare il ServiceManager nel mio gui per avviare una specifica operazione come

[self.core.serviceManager activateFriendsSync:nil onSuccess:nil]; 

Se voglio registrare un osservatore, ho solo passare un oggetto osservatore ed un selettore simili

[self.core.serviceManager activateFriendsSync:self onSuccess:@selector(myMethod:)]; 

Ultimo ma non meno importante la mia domanda/le: "L'architettura" funziona molto bene e stabile, ma vale la pena farlo? Crea troppe spese generali? Ha senso? Come tu, personalmente, implementa operazioni simultanee?

Miglior Henrik

P.S. Sentiti libero di modificare la mia domanda, porre domande (come commento), chiamami per questo pensiero.

Ho davvero avuto difficoltà a spiegarlo, fondamentalmente perché non sono un madrelingua inglese. E non fraintendermi. Non ho scritto questo post per sfoggiare in alcun modo.Tutto quello che voglio fare è imparare (e magari a scrivere la più avanzata iphone/Objective C questione)

risposta

1

Avete appena descritto un'architettura molto simile che sto usando in alcuni dei miei apps :)

ho il mio servizio strato responsabile restituzione di un insieme di oggetti immediatamente e poi tornare una versione aggiornata set dopo un po ', vale a dire

NSArray *stuff = [serviceManager getFriendsForUser:@"Bob"]; 

e poi, dopo che il server ha risposto, un NSNotification ricevuto che contiene un elenco aggiornato (di amici per Bob in questo caso).

A parte questo piccolo cambiamento, la tua architettura è la stessa!

È un bel po 'di lavoro per mettere tutto a punto, ma penso che ne valga la pena a lungo andare, poiché correggere bug/estendere il codice è molto più semplice.

+0

Ciao Dean, grazie ai tuoi approfondimenti. –

4

sì, se viene generato per le richieste di assistenza e si hanno molte chiamate da effettuare, quindi tale libreria non è (imo) overkill e ho scritto qualcosa di simile. questa struttura mi ha reso molto facile gestire un sistema complesso, con compiti molto complessi e variegati.

la differenza di progettazione principale che ho apportato era non per utilizzare NSNotification con un gestore servizi. invece, ho preferito utilizzare protocolli/tipi per i callback (a cui l'operazione contiene un riferimento). NSNotification è abbastanza pesante. in questo caso, l'operazione non mantiene i listener/gli oggetti notificati, ma gli ascoltatori mantengono l'operazione. se la relazione è 1-1, quindi consentire la cancellazione.

Un'altra considerazione importante è definire la filettatura in anticipo. consentire ai clienti di definire su quale thread vogliono ricevere la loro risposta. la ragione di ciò è che spesso c'è un vincolo o una voce logica per il callback se il destinatario/destinatario della notifica deve aggiornare l'interfaccia utente (ad esempio, stai utilizzando UIKit o AppKit). quindi, il creatore può dire all'operazione 'devi informarmi dal thread principale', o 'posso gestire la risposta da qualsiasi thread'. questo ridurrà notevolmente il codice controller/ascoltatore/osservatore e la possibilità di errori.

2

Per "operazioni di sub": per quanto riguarda la loro messa in coda, con l'operazione di genitore di essere una dipendenza (cfr -[ NSOperation addDependency: ]) di ciascuna delle sue operazioni bambino? NSOperationQueue può sequenziare l'intera serie di operazioni per te. Penso che questo sia semplice e naturale con cui lavorare.