NSMutableData高效率追加NSString

NSMutableData追加数据有如下两个方法:

- (void)appendBytes:(const void *)bytes length:(NSUInteger)length;
- (void)appendData:(NSData *)other;

它们都是针对二进制数据的。如果我们想追加NSString,该怎么办呢?

通常做法是先将NSString转换成了NSData,再进行追加。

NSMutableData* data = [[NSMutableData alloc]init];
NSString* string = @"hello, this is a 测试\n";
NSData* stringData = [string dataUsingEncoding:NSUTF8StringEncoding];
[data appendData:stringData];

闲暇的时候,看着这些代码,不禁要想,中间多了一次转换过程,是不是会影响效率呢?

我们可以这样思考,如果NSString转换为NSData时,仅仅是指针拷贝,没有拷贝数据,那么它是不会降低效率的;如果NSString转换为NSData时,进行了数据拷贝,那么它将会影响效率。因为相对于指针拷贝来说,数据块拷贝来拷贝去,要消耗大量CPU和时间。

接下来,我们只需要验证NSString转换为NSData时,究竟是指针拷贝还是数据拷贝。我们看下边的实验:

NSString* string = @"hello, this is a 测试\n";
NSData* data1 = [string dataUsingEncoding:NSUTF8StringEncoding];
NSData* data2 = [string dataUsingEncoding:NSUTF8StringEncoding];
NSData* data3 = [string dataUsingEncoding:NSUTF8StringEncoding];
NSLog(@"data1 address: %zd", [data1 bytes]);
NSLog(@"data2 address: %zd", [data2 bytes]);
NSLog(@"data3 address: %zd", [data3 bytes]);
我们对同一个NSString转换成三次NSData,并打印出三个NSData的内存指针。如果每次NSData转换,都没有对NSString进行数据拷贝,而仅仅是指针引用,那么三次打印结果,都应该是同一地址;如果三个地址都是不一样的,说明转换对NSString进行了数据拷贝。结果如下:

data1 address: 6243358272
data2 address: 6243358336
data3 address: 6243358368
三个打印都不一样,说明NSString转换为NSData时,进行了数据拷贝。同样的方法,我们也可以证明,cStringUsingEncoding: 方法所返回的 const char* 也是进行了数据拷贝。

总结:我们在最初对NSMutableData进行追加NSString时,对数据进行了两次拷贝:第一次将数据从NSString拷贝到了NSData,第二次将数据从NSData拷贝到了NSMutableData。

这显然是低效率的,那有没有仅进行一次数据拷贝的方法呢?答案是有,代码如下:

NSMutableData* data = [[NSMutableData alloc]init];
NSUInteger maxLenth = [string maximumLengthOfBytesUsingEncoding:NSUTF8StringEncoding];
NSUInteger offset = data.length;
data.length += maxLenth;
void* point = data.mutableBytes;
NSUInteger usedLength = 0;
NSRange remainingRang;
[string getBytes:point+offset maxLength:maxLenth usedLength:&usedLength encoding:NSUTF8StringEncoding options:NSStringEncodingConversionExternalRepresentation range:NSMakeRange(0, string.length) remainingRange:&remainingRang];
data.length -= maxLenth-usedLength;

我们使用了NSString的 getBytes:maxLength:usedLength:encoding:options:range:remainingRange: 方法。该方法就是在NSString转换为NSData时,将结果写入buffer指针的内存中,而我们只需要拿到NSMutableData的内存指针,便实现了只对数据进行一次拷贝的目的。

后来经测试实验证明,后者的代码效率,是前者的2~4倍。这里篇幅限制,不再贴出测试代码。

为了方便使用,写成了NSMutableData类别:

@interface NSMutableData (CDZMutableDataExtension)
- (void)appendString:(NSString*)string;     // use NSUTF8StringEncoding
- (void)appendString:(NSString*)string encoding:(NSStringEncoding)encoding;
@end

@implementation NSMutableData(CDZMutableDataExtension)
- (void)appendString:(NSString*)string{
    [self appendString:string encoding:NSUTF8StringEncoding];
}
- (void)appendString:(NSString*)string encoding:(NSStringEncoding)encoding{
    NSUInteger maxLenth = [string maximumLengthOfBytesUsingEncoding:encoding];
    NSUInteger offset = self.length;
    self.length += maxLenth;
    NSUInteger usedLength = 0;
    [string getBytes:self.mutableBytes+offset maxLength:maxLenth usedLength:&usedLength encoding:encoding options:NSStringEncodingConversionExternalRepresentation range:NSMakeRange(0, string.length) remainingRange:NULL];
    self.length -= maxLenth-usedLength;
}
@end

github地址: https://github.com/baight/CDZExtension

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值