2012-08-16 97 views
1

我想簡單地複製在一個NSData對象的形式包的內容,而不復制使用NSData的頭信息:dataWithBytesNoCopy不能與NSData的複製:dataWithBytesNoCopy

-(void)saveData:(NSData *)data 
{  
    const char* theBytes = [data bytes];  
    self.bodyData = [NSData dataWithBytesNoCopy:(char *)(theBytes + PACKET_HEADER_SIZE) 
             length:[data length] - PACKET_HEADER_SIZE 
            freeWhenDone:NO];  
} 

這個數據是什麼看起來像:

534e4150 00000000 0071534e 41500000 00000071 d5000008 5200e612 a180014a c4e947b9 35060225 bee8e729 00c21511 68a6dc52 c7177902 8343ea38 70bbc102 8e0fa9c4 0bbc8141 a1f2870e 1790d2a7 339487d4 e0c09de0 81487d4e 385e430f 9439c814 87ca1c38 5e1855aa 77667d4e 6643a9c7 0bbc1057 f0000710 4e1dcd12 801381be 06088e78 060c87e0 6088e780 60c8fc0c 111de018 78fc0c11 1de01832 3f030ccd f260c8fc 0c111de0 1879fc75 b3f93fcf e38ccde0 1879f819 6cfe4c3c fc0cb67e 01cf3f07 7ff880c8 a0301810 0a060201 00400000 c0f2b122 7e27910a f91843fc 408adf21 19891fc6 21722089 7fe26848 164550a9 ffc683f1 70d267ff cf253987 e71ffffe 468cc40c 545b7ffd 05da00ab ffee9fd2 f39fffff 710e1644 c8220000 84106102 000607ce 6811242a f84c9818 21be1de1 4ff10145 abe25a18 843fdfc3 7201885b a0fc7fe0 dd50c5c2 790c021c 57ff0b 

(前10個字節構成頭,我只是想複製包的正文)。

運行操作之後.. self.bodyData看起來是這樣的:

534e4150 00000000 0071d500 00085200 e612a180 014ac4e9 47b93506 0225bee8 e72900c2 151168a6 dc52c717 79028343 ea3870bb c1028e0f a9c40bbc 8141a1f2 870e1790 d2a73394 87d4e0c0 9de08148 7d4e385e 430f9439 c81487ca 1c385e18 55aa7766 7d4e6643 a9c70bbc 1057f000 07104e1d cd128013 81be0608 8e78060c 87e06088 e78060c8 fc0c111d e01878fc 0c111de0 18323f03 0ccdf260 c8fc0c11 1de01879 fc75b3f9 3fcfe38c cde01879 f8196cfe 4c3cfc0c b67e01cf 3f077ff8 80c8a030 18100a06 02010040 0000c0f2 b1227e27 910af918 43fc408a df211989 1fc62172 20897fe2 68481645 50a9ffc6 83f170d2 67ffcf25 3987e71f fffe468c c40c545b 7ffd05da 00abffee 9fd2f39f ffff710e 1644c822 00008410 61020006 07ce6811 242af84c 981821be 1de14ff1 0145abe2 5a18843f dfc37201 885ba0fc 7fe0dd50 c5c2790c 021c57ff 0bfa0098 11032e83 6a8213ff e32a1f28 a4873447 2282203f ffe4049a 311cd22c 6239a458 abffffe6 26489899 1a9aa4b3 536fffff fd8c4d98 d5264523 c6a93189 ffffffff fffec792 64526353 ec6a9322 91e3c7d0 04 

通知的前10個字節如何基本保持不變。而其剩餘的字節出於某種原因改變。我不知道爲什麼..建議?

更新: 以防萬一你想知道的數據是從,我真的開始.mp3文件,並使用音頻流媒體服務,然後使用GKSession發送它通過藍牙/ WIFI切片它來..以下是代碼:

static const int maxBufferSize = 0x10000; // limit maximum size to 64K 
static const int minBufferSize = 0x4000; // limit minimum size to 16K 

NSUInteger bufferByteSize = maxBufferSize; 
UInt32 numPacketsToRead = 0; 
NSUInteger headerByteSize = 10;    // header takes 10 bytes 


if (maxBufferSize < audioFile.maxPacketSize) bufferByteSize = audioFile.maxPacketSize; 
if (bufferByteSize < minBufferSize) bufferByteSize = minBufferSize; 

numPacketsToRead = bufferByteSize/audioFile.maxPacketSize; 

BOOL isVBR = YES; 

AudioStreamPacketDescription packetDescriptions[numPacketsToRead];  
SInt64 inStartingPacket = 0; 


do {   

    void *myBuffer = [[[NSMutableData alloc] initWithCapacity:bufferByteSize] mutableBytes]; 

    NSMutableData *packetData = [[NSMutableData alloc] initWithCapacity:bufferByteSize + headerByteSize]; 
    UInt32 outNumBytes = 0; 
    OSStatus result = 0; 

    result = AudioFileReadPackets (
            audioFile.fileID, 
            NO, 
            &outNumBytes, 
            isVBR ? packetDescriptions : 0, 
            inStartingPacket, 
            &numPacketsToRead, 
            myBuffer 
            ); 

    // add header info   
    [packetData rw_appendInt32:'SNAP']; // 0x534E4150 
    [packetData rw_appendInt32:0]; 
    [packetData rw_appendInt16:PacketTypeMusic]; 

    NSData *NSpacketData = packetData; 

    [packetData appendBytes:myBuffer length:outNumBytes]; 

    NSError *error; 

    NSLog(@"about to send out bytes"); 
    if (![_session sendDataToAllPeers:NSpacketData withDataMode:GKSendDataReliable error:&error]) 
    { 
     NSLog(@"Error sending data to clients: %@", error); 
    }   
} while (numPacketsToRead < audioFile.packetsCount); 
+0

如何你是否確信你的原始NSData對象在你完成你的副本之前不會被髮布或修改? – 2012-08-16 12:27:15

+0

(我的建議是不使用這個功能 - 這在非熟練的手中是相當危險的。) – 2012-08-16 12:29:08

+0

@HotLicks我從來沒有想過釋放內存部分,因爲我使用ARC .. – abbood 2012-08-16 13:17:30

回答

4

使用dataBytesWithNoCopy意味着該NSData對象將只保留一個指針到你給它的數據。在你的情況下,你給它的數據是由另一個數據對象(作爲參數傳入的)管理的。

如果你給原始數據的NSData,NSData的對象實際上是唯一,而數據是有效的有效。現在

,同樣的方法具有另一個說法,freeWhenDone它告訴NSData對象它是否擁有數據。如果你分配緩衝區,並且你希望NSData在完成時釋放它,然後傳遞YES。再次,在你的情況下,因爲你的數據是由另一個NSData對象擁有的,所以你告訴它NO。

但是,以後,當您訪問伊娃bodyData它的數據仍然會指向回從數據NSData對象,你給了它。如果該對象發生了變化,或者已釋放,那麼你的指針將指向到一些未知的一塊內存。

如果你想創建數據的副本,那麼你必須使用標準的初始化。

如果你想使用noCopy,那麼你必須保證原始數據的生活至少只要NSData的使用它。

編輯

如果你想這樣做 「標準」 的方式...

char const *bytes = data.bytes; 
self.bodyData = [NSData dataWithBytes:bytes + PACKET_HEADER_SIZE 
           length:data.length - PACKET_HEADER_SIZE];  

現在,這將創建一個與的NSData字節的副本。請注意,它會爲您提供的字節分配空間,然後它會複製這些字節。

「無副本」版本只是「使用」你給它的數據指針 - 如果你告訴它這樣做,它將在完成時釋放緩衝區。這是用於性能的原因,但是如果你使用它,你必須確保你給它的指針至少和數據對象本身一樣長。

在C語言中,如果你想有一個緩衝區,你必須分配和自己複製...

size_t length = data.length - PACKET_HEADER_SIZE; 
void * buffer = malloc(length); 
memcpy(buffer, ((char const *)data.bytes) + PACKET_HEADER_SIZE, length); 
+1

糟糕。應該仔細閱讀。雖然點相同,但是原始數據項被解除分配。將相應地編輯。謝謝。 – 2012-08-16 13:02:23

+0

你能舉個例子說明'標準初始化器'是什麼意思嗎?另外,如果這個操作在哪裏使用良好的'C .. ..它會是什麼樣子?我試過 size_t size = [data length]; int * storage =(int *)malloc(size); const int * theBytes = [data bytes]; memcpy(storage,(int *)(theBytes + PACKET_HEADER_SIZE),size - PACKET_HEADER_SIZE); 但得到意想不到的結果 – abbood 2012-08-16 13:20:47

+0

哎呀對不起,我沒有看到你的編輯,然後提交我自己的答案..信貸給你一個全面的答案 – abbood 2012-08-17 10:50:48

-1

試試這個代碼,看看它是否會工作:

int offset = 10; 
NSRange dataRange; 
dataRange.length = [data length] - offset; 
dataRange.location = offset; 

void *buffer = malloc(dataRange.length); 
[data getBytes:buffer range:dataRange]; 
self.bodyData = [[NSData alloc] initWithBytesNoCopy:buffer length:dataRange.length]; 
free(buffer); //Make sure your property has either retain attribute (or strong if using ARC) 
+0

這有點違背了使用nocopy版本的目的...... – 2012-08-16 12:47:37

+0

由於某種原因您的代碼在這個錯誤消息中返回: malloc :對象0x1e7b00的***錯誤:被釋放的指針未被分配 ***在malloc_error_break中設置一個斷點來調試 – abbood 2012-08-16 13:16:24

+0

@graver我的不好,它確定bodyData的聲明如下所示後工作: property(nonatomic,strong)NSData * bodyData; – abbood 2012-08-16 13:24:13

0

這個工作,但通過使用C,不客觀的C:

size_t size = [data length]; 
short * buffer = (short *)malloc(size); 
const short* theBytes = [data bytes]; 
short offset = PACKET_HEADER_SIZE/2; 


memcpy(buffer, (short *)(theBytes + offset), size - PACKET_HEADER_SIZE); 

self.bodyData = [NSData dataWithBytes:buffer length:size - PACKET_HEADER_SIZE]; 
free(buffer);