NSData dataWithBytesNoCopy 来自 NSInputStream

发布于 2024-09-26 02:59:31 字数 978 浏览 5 评论 0原文

我正在研究将图像数据从文件转码为 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);

I'm working on transcoding image data from a file to a base64 encoded string and then back to bytes as the file is read using NSStream. I think I'm almost there, but I keep running into EXC_BAD_ACCESS at various points during the conversion.

I'm fairly new to the world of NSStream and buffers so feel free to let me know if I'm taking the absolute wrong approach here.

Here's what I've got so far:

// 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);

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

落墨 2024-10-03 02:59:31

这里有几个问题:

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

这并不像您的评论所说的那样。您刚刚所做的就是在 self.buffer[self.bufferOffset] 处分配一个与 size_t (4 字节或 8 字节无符号整数)相同大小的缓冲区基本上,您尝试分配一个本质上随机的缓冲区尺寸。如果大小太大,您将得到 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];

该方法的其余部分应该是相同的,除了您不再有可以释放的缓冲区(事实上您之前确实没有)。

Several issues here:

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

This does not do what your comment says it does. What you have just done is allocated a buffer the same size as the size_t (4 byte or 8 byte unsigned integer) at self.buffer[self.bufferOffset] Basically you try to allocate a buffer of essentially random size. If the size is too big, you'll get NULL back and that is probably what is causing your crashes.

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

This does not do what you think it does. sizeof(base64buffer) is either 4 or 8 depending on whether you are compiling in 32 bit or 64 bit mode. It is the size of the pointer, not the size of the buffer.

free(base64buffer);

When you created the initial NSData, you said yes to "freeWhenDone". This means the NSData took ownership of base64buffer and will try to free it when it is deallocated. Since you have already freed it, that operation will fail in unpredictable nasty ways.


How can we fix this? Try something like this:

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];

The rest of the method should be the same except you don't have a buffer to free anymore (in fact you didn't before really).

ゃ人海孤独症 2024-10-03 02:59:31
NSData *dataToEncode = [NSData dataWithBytesNoCopy:base64buffer length:sizeof(base64buffer) freeWhenDone:YES];

当 dataToEncode 释放时,此行将执行 free(base64buffer) 操作,因为 freeWhenDone:YES。因此,您将两次释放相同的内存空间。

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

This line will do free(base64buffer) when the dataToEncode deallocated, because the freeWhenDone:YES. So, you will free the same memory space twice.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文