Attualmente sto lavorando ad un'applicazione per iPhone e ho una libreria di una terza parte che ha un comportamento asincrono, ma che mi piacerebbe racchiudere la mia classe e farla sembrare sincrona.Come racchiudere una classe asincrona per renderla sincrona? Usa NSRunLoop?
La classe centrale in questa libreria, chiamiamola classe Connection, ha diverse funzioni che risolvono il risultato finale quando vengono chiamati i metodi su un'istanza di una classe delegata. Quello che sto cercando di fare è racchiudere questa classe e delegare in modo che sembri sincrono anziché asincrono. Se lo facessi in Java, userei FutureTask o CountdownLatch o semplicemente join(). Ma non sono sicuro che sia il modo migliore per farlo nell'Obiettivo C.
Ho iniziato creando un estensore NSTreadread, NFCThread, che è conforme al protocollo delegato sopra menzionato. L'idea è che vorrei init e NFCThread, passare l'istanza NFCThread al metodo setDelegate di Connection, avviare il thread e quindi chiamare un metodo asincrono su Connection. La mia aspettativa è che uno dei tre metodi delegate sull'istanza NFCThread venga chiamato alla fine causando l'uscita del thread.
Per simulare un join ho fatto quanto segue. Ho aggiunto un NSConditionalLock a NFCThread:
joinLock = [[NSConditionLock alloc] initWithCondition:NO];
Il codice attorno alla chiamata a Connection sembra qualcosa di simile:
NFCThread *t = [[NFCThread alloc] init];
[connection setDelegate:t];
[t start];
[connection openSession];
// Process errors, etc...
[t.joinLock lockWhenCondition:YES];
[t.joinLock unlock];
[t release];
[connection setDelegate:nil];
Il protocollo per il delegato ha tre metodi. In NFCThread ho implementato ogni metodo qualcosa di simile:
- (void)didReceiveMessage:(CommandType)cmdType
data:(NSString *)responseData
length:(NSInteger)length {
NSLog(@"didReceiveMessage");
// Do something with data and cmdType...
[joinLock lock];
[joinLock unlockWithCondition:YES];
callBackInvoked = YES;
}
ho sovraccaricato il metodo principale di NFCThread in modo che solo loop continuo. Qualcosa di simile a questo:
while (!callBackInvoked) { ; }
ho scoperto che questo non è davvero una buona idea, dal momento che provoca l'utilizzo della CPU di passare attraverso il tetto. Così, invece ho provato ad utilizzare un ciclo di esecuzione da parte di alcuni esempi che ho trovato su questo sito:
NSRunLoop *runLoop = [NSRunLoop currentRunLoop];
[runLoop addPort:[NSMachPort port] forMode:NSDefaultRunLoopMode];
while (!callBackInvoked) {
[runLoop runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
}
In entrambi i miei implementazioni thread principale è sempre bloccato e sembra che nessuno dei metodi delegato vengono mai chiamati. Tuttavia, so che la libreria funziona correttamente e che normalmente vengono chiamate le chiamate ai metodi delegati.
Mi sento come se mi mancasse qualcosa di ovvio qui. Qualsiasi aiuto molto apprezzato.
Rich
Grazie, Firoze. Sì, la nostra intenzione è di bloccare la nostra chiamata sincrona. Questa libreria di terze parti si interfaccia effettivamente con una scheda SD, ma penso che sia solo un dettaglio. Inoltre, dopo un'attenta ispezione, ho appena determinato che le chiamate ai metodi delegati avvengono anche sul thread principale. Questo potrebbe rendere questa intera discussione discutibile? – richever
Beh, non sono sicuro che sia discutibile. Il fatto è che se vuoi che la chiamata blocchi, e blocchi il thread principale, allora questa altra libreria non può finire il suo lavoro. Quindi una risposta sarebbe quella di effettuare la chiamata sincrona da un thread diverso, che bloccherebbe * quel * thread, ma consentirà comunque al thread principale di continuare a funzionare normalmente. Ovviamente se si finisce per creare e bloccare molti thread in questo modo, non va molto bene. In ogni caso, penserei a * perché * vuoi questa sincronizzazione e magari pensare a un modo non bloccante per fare la stessa cosa (richiede sapere più di quello che stai cercando di fare qui) –
Sto chiamando il metodo di blocco in una discussione diversa ora, come hai suggerito Firoze, e questo sembra funzionare. Una specie di. Vedi la mia domanda seguente: http://stackoverflow.com/questions/3444557/error-at-nsrunloop-after-returning-from-thread-method-with-nsautoreleasepool – richever