1

我试图简单地以 NSData 对象的形式复​​制数据包的内容,而不使用 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); 
4

3 回答 3

4

使用dataBytesWithNoCopy意味着 NSData 对象将只保留指向您提供的数据的指针。在您的情况下,您提供的数据由另一个数据对象(作为参数传入的对象)管理。

如果您将原始数据提供给 NSData,则 NSData 对象实际上仅在该数据有效时才有效。

现在,同样的方法有另一个参数,freeWhenDone它告诉 NSData 对象它是否拥有数据。如果您分配缓冲区,并且您希望 NSData 在完成后释放它,则传递 YES。同样,在您的情况下,由于您的数据归另一个 NSData 对象所有,因此您告诉它不。

但是,稍后,当您访问 iVar 时,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);
于 2012-08-16T12:52:56.663 回答
0

这可行,但使用 C,而不是 Objective 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);
于 2012-08-17T07:55:13.933 回答
-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)
于 2012-08-16T12:41:02.273 回答