1

NSData:dataWithBytesNoCopy を使用してヘッダー情報をコピーせずに、パケットの内容を NSData オブジェクトの形式で単純にコピーしようとしています

-(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 を使用して bluetooth/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

UsingdataBytesWithNoCopyは、NSData オブジェクトが、指定したデータへのポインタを保持するだけであることを意味します。あなたの場合、あなたが与えているデータは別のデータオブジェクト(パラメータとして渡されたもの)によって管理されています。

生データを NSData に渡す場合、NSData オブジェクトは実際にはそのデータが有効である間のみ有効です。

現在、同じメソッドには別の引数がfreeWhenDoneあり、NSData オブジェクトがデータを所有しているかどうかを伝えます。バッファーを割り当て、完了時に NSData に解放させたい場合は、YES を渡します。繰り返しますが、あなたの場合、データは別の NSData オブジェクトによって所有されているため、NO と伝えます。

ただし、後で 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

これは機能しますが、Objective 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);
于 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 に答える