NSMutableData如何删除字节?

31

我可以使用appendData方法轻松地向NSMutableData实例中添加字节,但是我没有看到任何类似于删除数据的方法。是我忽略了什么,还是需要创建一个新对象并仅复制我需要的字节?

我可以使用appendData方法轻松地向NSMutableData实例中添加字节,但是似乎没有类似的方法用于删除数据。我是否忽略了某些内容? 如果要删除数据,您可能需要创建一个新对象,并仅复制所需的字节。请注意保留HTML标记。
4个回答

78

请参阅以下方法的文档:

- (void)replaceBytesInRange:(NSRange)range 
    withBytes:(const void *)replacementBytes 
    length:(NSUInteger)replacementLength

苹果公司的文档中如下所述:

如果范围的长度与replacementLength不相等,则会调整接收器的大小以容纳新的字节。 接收器中范围之后的所有字节都将被移动以容纳新的字节。因此,您可以传递NULL作为replacementBytes0作为replacementLength删除范围内的字节。您还可以用比范围长度更多的字节替换范围(可能是零长度),这会产生插入效果(或“替换一些并插入更多”)。

要从末尾删除10个字节,请使用:

data.length = data.length - 10;

也可以通过replaceBytesInRange来实现,但实际上速度要快得多,因为字节并没有真正被移除。相反,只有内部大小变量被更改,NSMutableData将表现为字节已被移除。即,这是一个O(1)操作(这意味着无论您删除多少字节,执行时间始终相同),而且速度非常快。

要从开头移除10个字节,请使用:

[data replaceBytesInRange:NSMakeRange(0, 10) withBytes:NULL length:0];

要在中间删除10个字节(例如在20个字节后),请使用:

[data replaceBytesInRange:NSMakeRange(20, 10) withBytes:NULL length:0];

replaceBytesInRange 是一个O(n)的操作。执行此操作所需的时间取决于数据对象包含的字节数以及您要移除的位置,因为移除位置右侧的所有字节都必须向左移动。尽管如此,它仍然相当快,只受计算机内存(RAM)吞吐量的限制。如果您有10 MB的数据,并从前面删除1 MB,则将复制9 MB以填补刚刚删除的1 MB的空缺。因此,操作的速度取决于您的系统可以多快地将9 MB的RAM从一个地址移动到另一个地址(在我的系统上,这需要0.2毫秒才能完成9MB的移动)。


这是一个很好的答案,尽管它是从一个赞数较少且现在已经不相关的答案中派生出来的。你能否修改它,使其成为一个独立的答案?+1 - Dan Rosenstark
1
@Yar:当然可以。我删除了对其他答案的引用。 - Mecki
今天我又回到了这个答案,当时正在寻找“您还可以用比范围长度更多的字节替换范围(可能为零长度),这将具有插入(或“替换一些并插入更多”)的效果。”虽然离题但相关。谢谢! - Dan Rosenstark
我使用了这些方法来删除前面的两个字节和末尾的一个字节。非常有用 - 对于大数据集可能会占用较多内存。但它的效果非常好... - Ashu Joshi
是的,但它基本上不像setLength一样缩小NSData...我想偏移前指针,这样整个结构就会变小。 - Peter Lapisu
显示剩余3条评论

3

由于NSMutableData与CFMutableDataRef之间是toll-free bridged,因此您可以使用CFDataDeleteBytes()函数:

NSMutableData *data = ...
CFDataDeleteBytes((CFMutableDataRef)data, CFRangeMake(3, 4));

3
小心谨慎,沿着这条路走会遇到性能问题。如果你只进行相对较少的编辑或者处理小量数据,那就没什么大问题。但如果是更大的数据或者需要频繁处理且对性能敏感的情况,考虑使用某种优化的数据结构。 - bbum
1
为什么要使用CoreFoundation,如果你可以使用NSMutableData方法replaceBytesInRange呢?根据文档,如果替换字节指针为NULL且替换长度也为0,则该方法会删除范围内的字节。 - Mecki
1
虽然这个解决方案可行,但我认为Mecki的更加简洁,应该被标记为已接受。+1 给Mecki,但是对于找到第二好的解决方案不会有任何扣分。(如果在底层使用了另一个解决方案,那将是很有趣的!:) - Olie
@bbum你的评论也适用于其他(已接受)答案吗? - Dan Rosenstark
是的。每当您开始以可能改变总长度的方式操纵数据时,您很容易在整个代码中复制大量字节。 - bbum
显示剩余2条评论

1

如果您要删除的数据位于末尾,可以使用

[NSMutableDataInstance setLength:[NSMutableDataInstance length] - n];

或使用 obj-c 2.0 语法

NSMutableDataInstance.length -= n;

对于比这更复杂的任何事情,我建议操纵原始数据。


谢谢你的建议!不过我正在尝试从前面删除 :) - Kyle

0

我看到这个线程有答案,但是这可能是有价值的补充。要从NSMuttableData中删除所有字节,您可以创建新的Data并将其复制到原始数据中:

[myData setData:[NSData dataWithBytes:NULL length:0]];

这个很棒。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接