2016-06-17 9 views
1

Так что мое приложение работает по этим направлениям:Как надежно извлекать объекты NSData из NSInputStream в XCode

  1. IPOD непрерывно посылает NSDictionaries, которые содержат: изображение, закодированное в формате JPEG и некоторых свойств изображения, как NSStrings.
  2. NSDictionary кодируется с использованием NSPropertyListSerialization с форматом BinaryFormat_v1_0 и отправляется в пакетах с 1024 байтами через NSStream на центральный компьютер, на котором установлено приложение OSX.
  3. Приложение OSX принимает пакеты данных, непрерывно добавляя к одному объекту NSMutableData, пока не увидит первый пакет следующего объекта NSData (который в двоичном формате, который я нашел, запускается как «bplist»).
  4. NSData преобразуется обратно в NSDictionary, который будет использоваться приложением OSX, вызывая NSPropertyListSerialization.
  5. После того, как NSData была успешно преобразована (или нет), объект NSData возвращается к нулю, чтобы начать чтение следующего раунда пакетов.

Еще несколько примечаний: потоки NSInputStream и NSOutput работают в текущем RunLoop соответствующего устройства в NSDefaultRunLoopMode.

При выполнении этого процесса, иногда преобразование обратно NSDictionary отлично работает без ошибок (около 1/3 из попыток), но в других случаях возвращает преобразование эту ошибку:

Error: Failed to convert NSData to NSDict : Error Domain=NSCocoaErrorDomain Code=3840 "Unexpected character b at line 1" UserInfo={NSDebugDescription=Unexpected character b at line 1, kCFPropertyListOldStyleParsingError=Error Domain=NSCocoaErrorDomain Code=3840 "Conversion of string failed." UserInfo={NSDebugDescription=Conversion of string failed.}}

После являются части программы, анализирующие данные из потока:

... метод для обработки потоковых событий:

-(void)stream:(NSStream *)aStream handleEvent:(NSStreamEvent)eventCode { 
switch(eventCode) { 
    case NSStreamEventHasBytesAvailable: { 

     uint8_t buf[1024]; 
     unsigned int len = (unsigned)[(NSInputStream *)aStream read:buf maxLength:1024]; 

     if(len) { 
      [self handleEventBuffer:buf WithLength:len]; 
     } 
... 

... и метод, который тот KES забота о данных:

-(void)handleEventBuffer:(uint8_t*)buf WithLength:(unsigned int)len { 
... 
NSString *bufStr = [NSString stringWithFormat:@"%s",(const char*)buf]; 
     if ([bufStr containsString:@"bplist00"] && [self.cameraData length] > 0) { 
      // Detected new file, enter in all the old data and reset for new data 
      NSError *error; 
      NSDictionary *tempDict = [[NSDictionary alloc] init]; 

      tempDict = [NSPropertyListSerialization propertyListWithData:self.cameraData 
                  options:0 
                   format:NULL 
                   error:&error]; 

      if (error != nil) { 
       // Expected good file but no good file, erase and restart 
       NSLog(@"Error: Failed to convert NSData to NSDict : %@", [error description]); 
       [self.cameraData setLength:0]; 
      } 
... 
      [self.cameraData setLength:0]; 
      [self.cameraData appendBytes:buf length:len]; 

     } else { 
      // Still recieving data 
      [self.cameraData appendBytes:buf length:len]; 
     } 

Итак, вопрос, который я получаю на это:

  • Как я могу исправить мой метод синтаксического анализа, чтобы дать мне надежные результаты, которые не случайно не в состоянии конвертировать?
  • ИЛИ есть ли лучший способ, чем это, для анализа потоков буфера для этой цели?
  • ИЛИ Я просто делаю что-то глупое или пропавшее без вести что-то очевидное?

ответ

1

Кажется, что вы полагаетесь на каждую запись в поток, в результате чего сопоставление читается одинакового размера, вы знаете, что это гарантировано NSStream? Если нет, то любое чтение может содержать части из двух (или более) ваших закодированных словарей, и вы получите ошибки синтаксического анализа, которые вы видите.

Альтернативный подход:

Для каждого кодированного словаря отправить:

Написать конец:

  1. Отправить сообщение, содержащее размер в байтах кодированного словаря, который будет следовать.
  2. Написать кодированный словарь в кусках, последний кусок может быть коротким
  3. Repeat

Читать конец:

  1. Прочитать сообщение размера, указав его точную длину в байтах.
  2. Прочитайте закодированный словарь в кусках, убедившись, что вы прочитали только количество байтов, о которых сообщает (1).
  3. Повторите.

При условии, что вы используете надежный поток связи, это позволит вам надежно прочитать каждый закодированный словарь. Это позволяет избежать попыток выяснить, где находится граница между каждым закодированным словарем, поскольку эта информация является частью вашего протокола.

HTH

+0

Удивительно, что это трюк, так много времени занимался обработкой событий, но теперь он работает плавно. Благодаря! – blakemacnair