2017-02-09 5 views
1

Je travaille actuellement avec CBPeripheralDelegate pour échanger des messages entre un périphérique iOS et une clé USB Bluetooth Low Energy. Je dois implémenter la méthode sendMessage: qui écrit des octets de données à l'aide d'un service d'émulation série. Cette méthode doit envoyer une trame de 15 octets (ou moins) à la fois, en attendant un accusé de réception du dongle avant d'envoyer le suivant.Bloquer une boucle for jusqu'à ce qu'une méthode déléguée soit renvoyée

Ci-dessous mon code:

- (void)sendMessage:(NSData *)message { 
    NSArray *chuncks = [self splitMessage:message]; 
    for (NSUInteger i = 0; i < chunks.count; i++) { 
     NSData *chunk = [chunks objectAtIndex:i]; 
     [self sendChunk:chunk withId:i ofChunks:chances.count]; 
     // Wait for the ack to be received 
    } 
} 

- (void)sendChunk:(NSData *)chunk withId:(NSInteger)id ofChunks:(NSInteger)count { 
    NSMutableData *frame = [NSMutableData new]; 
    // Here I build my frame, adding header, current chunk ID and total number of chunks, then I call... 
    [serialEmulationService writeValue:frame forCharacteristic:serialEmulationServiceCharacteristic type:CBCharacteristicWriteWithResponse]; 
} 

Maintenant la question: la boucle for dans la méthode sendMessage: doit être bloqué jusqu'à ce que le périphérique ne recevra pas le ack, peut-être avec un délai d'attente. Cet accusé de réception est reçu à l'intérieur de la méthode déléguée - (void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(nonnull CBCharacteristic *)characteristic error:(nullable NSError *)error, donc ici je dois redémarrer la boucle for précédemment bloquée.

Quelle est la meilleure pratique pour cette situation particulière? Je voudrais utiliser les sémaphores de GCD, mais je n'arrive pas à comprendre comment implémenter des appels synchrones et n'arrive pas à comprendre l'un des nombreux exemples en ligne qui expliquent cette technique.

Est-ce que quelqu'un pourrait me donner un coup de main?

Répondre

1

Que diriez-vous sauter la boucle for entièrement ...

@property (nonatomic) NSMutableArray *chunks; 
@property (nonatomic) NSInteger chunkId; 

- (void)sendMessage:(NSData *)message { 
    self.chunks = [[self splitMessage:message] mutableCopy]; 
    self.chunkId = 0; 

    [self sendNextChunk]; 
} 

- (void sendNextChunk { 

    NSData * chunk = self.chunks.firstObject; 

    if chunk == nil { 
     return 
    } 

    [self.chunks removeObjectAtIndex: 0]; 
    [self sendChunk:chunk withId:chunkId++ ofChunks:chances.count]; 
}  


- (void)sendChunk:(NSData *)chunk withId:(NSInteger)id ofChunks:(NSInteger)count { 
    NSMutableData *frame = [NSMutableData new]; 
    // Here I build my frame, adding header, current chunk ID and total number of chunks, then I call... 
    [serialEmulationService writeValue:frame forCharacteristic:serialEmulationServiceCharacteristic type:CBCharacteristicWriteWithResponse]; 
} 

- (void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(nonnull CBCharacteristic *)characteristic error:(nullable NSError *)error { 
    [self sendNextChunk]; 
} 
+0

assez facile, je vous remercie. L'approche la plus simple et directe. Juste une petite remarque: nécessaire pour définir une propriété pour la taille du tableau 'chunks' d'origine, car elle diminue à chaque envoi de bloc. – Dree

0

L'approche serait d'utiliser le Notification. Créez separate method pour lancer votre for loop. Cette méthode observera pour le Notification, à l'intérieur de la méthode delegate après le Notification. Dans le sendMessage: continuer à ajouter le message à une propriété.