NSData dataWithBytesNoCopy из NSInputStream - PullRequest
       17

NSData dataWithBytesNoCopy из NSInputStream

0 голосов
/ 04 октября 2010

Я работаю над перекодированием данных изображения из файла в строку в кодировке base64, а затем обратно в байты при чтении файла с использованием NSStream. Я думаю, что я почти там, но я продолжаю сталкиваться с EXC_BAD_ACCESS в различных точках во время преобразования.

Я довольно новичок в мире NSStream и буферов, поэтому не стесняйтесь, дайте мне знать, если я выберу абсолютно неправильный подход.

Вот что у меня так далеко:

// Copy the bytes from our file input stream buffer
void *base64buffer = malloc(self.buffer[self.bufferOffset]);

// Convert the bytes to NSData for the base64 encode
NSData *dataToEncode = [NSData dataWithBytesNoCopy:base64buffer length:sizeof(base64buffer) freeWhenDone:YES];

// Convert our NSData into a base64 encoded string
NSString *base64EncodedData = [dataToEncode base64EncodedString];

// Convert our base64 encoded string back into NSData
NSData *encodedData = [base64EncodedData dataUsingEncoding:NSUTF8StringEncoding];

// Write the bytes to our output stream
bytesWritten = [self.producerStream write:[encodedData bytes] maxLength:[encodedData length]];

// Clean up
dataToEncode = nil;
base64EncodedData = nil;
encodedData = nil;
free(base64buffer);

Ответы [ 2 ]

5 голосов
/ 04 октября 2010

Несколько вопросов здесь:

// Copy the bytes from our file input stream buffer
void *base64buffer = malloc(self.buffer[self.bufferOffset]);

Это не делает то, что говорит ваш комментарий.То, что вы только что сделали, - это выделение буфера того же размера, что и size_t (4-байтовое или 8-байтовое целое число без знака) на self.buffer[self.bufferOffset] В основном вы пытаетесь выделить буфер практически случайного размера.Если размер слишком велик, вы получите NULL, и это, вероятно, является причиной ваших сбоев.

// Convert the bytes to NSData for the base64 encode
NSData *dataToEncode = [NSData dataWithBytesNoCopy:base64buffer length:sizeof(base64buffer) freeWhenDone:YES];

Это не делает то, что вы думаете, что делает.sizeof(base64buffer) - это 4 или 8, в зависимости от того, используете ли вы 32-битный или 64-битный режим.Это размер указателя, а не размер буфера.

free(base64buffer);

Когда вы создали исходные данные NSData, вы сказали yes "freeWhenDone".Это означает, что NSData стал владельцем base64buffer и попытается освободить его, когда он будет освобожден.Так как вы уже освободили его, эта операция завершится непредсказуемым неприятным образом.


Как мы можем это исправить?Попробуйте что-то вроде этого:

size_t bufferLengthInBytes = .... // you'll need to figure out how to get this

// Next, instead of mallocing my own buffer for the data, I'll let the runtime do it for me.
// I'm assuming that self.buffer is a pointer to the bytes you want to copy.
NSData* dataToEncode = [NSData dataWithBytes: self.buffer length:bufferLengthInBytes];

// I'm not sure where the method base64EncodedString comes from.  I assume you have a category to do this.
NSString *base64EncodedString = [dataToEncode base64EncodedString];

Остальная часть метода должна быть такой же, за исключением того, что у вас больше нет буфера для освобождения (на самом деле вы раньше этого не делали).

3 голосов
/ 04 октября 2010
NSData *dataToEncode = [NSData dataWithBytesNoCopy:base64buffer length:sizeof(base64buffer) freeWhenDone:YES];

Эта строка освобождается (base64buffer), когда освобождается dataToEncode, потому что freeWhenDone: YES . Таким образом, вы освободите одно и то же пространство памяти дважды.

...