开发者

New NSData with range of old NSData maintaining bytes

开发者 https://www.devze.com 2022-12-26 15:38 出处:网络
I have a fairly large NSData (or NSMutableData if necessary) object which I want to take a small chunk out of and leave the rest. Since I\'m working with large amounts of NSData bytes, I don\'t want t

I have a fairly large NSData (or NSMutableData if necessary) object which I want to take a small chunk out of and leave the rest. Since I'm working with large amounts of NSData bytes, I don't want to make a big copy, but instead just truncate the existing bytes. Basically:

  • NSData *source: < a few bytes I want to discard > + 开发者_运维知识库< big chunk of bytes I want to keep >
  • NSData *destination: < big chunk of bytes I want to keep >

There are truncation methods in NSMutableData, but they only truncate the end of it, whereas I want to truncate the beginning. My thoughts are to do this with the methods:

Note that I used the wrong (copying) method in the original posting. I've edited and fixed it

- (const void *)bytes

and

- initWithBytesNoCopy:length:freeWhenDone:

However, I'm trying to figure out how to manage memory with these. I'm guessing the process will be like this (I've placed ????s where I don't know what to do):

// Get bytes
const unsigned char *bytes = (const unsigned char *)[source bytes];

// Offset the start
bytes += myStart;

// Somehow (m)alloc the memory which will be freed up in the following step
?????

// Release the source, now that I've allocated the bytes
[source release];

// Create a new data, recycling the bytes so they don't have to be copied
NSData destination = [[NSData alloc]
                      initWithBytesNoCopy:bytes
                      length:myLength
                      freeWhenDone:YES];

Thanks for the help!


Is this what you want?

NSData *destination = [NSData dataWithBytes:((char *)source.bytes) + myStart
                                     length:myLength];

I know you said "I don't want to make a big copy," but this only does the same copy you were doing with getBytes:length: in your example, so this may be okay to you.

There's also replaceBytesInRange:withBytes:length:, which you might use like this:

[source setLength:myStart + myLength];
[source replaceBytesInRange:NSMakeRange(0, myStart)
                  withBytes:NULL
                     length:0];

But the doc's don't say how that method works (no performance characteristics), and source needs to be an NSMutableData.


depending on the context, the solutions can be different. I will assume that you need a method that would return an autoreleased NSData object with the specified range:

- (NSData *)getSubData:(NSData *)source withRange:(NSRange)range
{
    UInt8 bytes[range.length];
    [source getBytes:&bytes range:range];
    NSData *result = [[NSData alloc] initWithBytes:bytes length:sizeof(bytes)];
    return [result autorelease];
}

Of course, you can make it a class method and put it into some kind of "utils" class or create an extension over NSData...


If you want to avoid copying memory blocks, you can use the dataWithBytesNoCopy to keep the old buffer with a certain offset. In this example we "remove" the first 2 bytes:

source = [NSData dataWithBytesNoCopy:(char*)source.bytes + 2 length:source.length - 2];

For the sake of example simplicity, boundary check is skipped, please add it as it convenient for you. Available in iOS 2.0 and later.


There's also an NSData method -[subdataWithRange:(NSRange)range] that could do the trick. I have no idea what the performance looks like (I'd imagine it does a copy or two, but I don't know for certain). It can be used like:

NSData *destination = [source subdataWithRange:NSMakeRange(0, lengthIWant)];
0

精彩评论

暂无评论...
验证码 换一张
取 消