2010-10-04 3 views
0

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

Я довольно новичок в мире 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); 
+0

Во-первых, malloc не копирует байты, он выделяет новую память, так что это огромная ошибка; во-вторых, ваш плохой доступ исходит от двойной бесплатной. Вы спросили, что NSData будет создано с помощью NoCopy, поэтому он использует ваш буфер памяти в качестве хранилища для поддержки, и вы устанавливаете freeWhenDone равным YES, поэтому, когда этот объект NSData уходит, он освобождает ваш буфер. Затем вы также бесплатно освобождаете свой буфер; либо установите это значение NO, либо не освободите base64buffer самостоятельно. –

ответ

5

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

// 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, вы сказали да «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]; 

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

+0

Спасибо. Это прекрасно работало. Что касается bufferLengthInBytes, я использую: size_t bufferLengthInBytes = sizeof (self.buffer); Особая благодарность Торо, ваши советы помогли мне вместе. – frsh

+0

@frsh: Хороший способ выразить свою благодарность Торо - это проголосовать за его ответ. – JeremyP

3
NSData *dataToEncode = [NSData dataWithBytesNoCopy:base64buffer length:sizeof(base64buffer) freeWhenDone:YES]; 

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

Смежные вопросы