我想将MIDI信息打包到NSData对象中。
int messageType = 3; // 0-15
int channel = 5; // 0-15
int data1 = 56; // 0-127
int data2 = 78; // 0-127
int packed = data2;
packed += data1 * 127;
packed += channel * 16129; // 127^2
packed += messageType * 258064; // 127^2 * 16
NSLog(@"packed %d", packed);
NSData *packedData = [NSData dataWithBytes:&packed length:sizeof(packed)];
int recovered;
[packedData getBytes:&recovered];
NSLog(@"recovered %d", recovered);
这非常有效,虽然我为自己感到自豪,但我知道转换为字节并没有正确完成:它应该是一个没有大量加法和乘法的直接转换。怎么办呢?
编辑:我现在知道我可以这样做
char theBytes[] = {messageType, channel, data1, data2};
NSData *packedData = [NSData dataWithBytes:&theBytes length:sizeof(theBytes)];
并在Java方面
byte[] byteBuffer = new byte[4]; // Receive buffer
while (in.read(byteBuffer) != -1) {
System.out.println("data2=" + byteBuffer[3]);
}
它会起作用,但我想要一个只有3个字节的NSData的解决方案。
答案 0 :(得分:3)
就个人而言,我会选择NSString:
NSString *dataString = [NSString stringWithFormat:@"%i+%i+%i+%i", messageType, channel, data1, data2];
NSData *packedData = [dataString dataUsingEncoding:NSUTF8StringEncoding];
易于使用,易于转移。拆包有点复杂,但也不困难。
NSScanner *scanner = [NSScanner scannerWithString:[[[NSString alloc] initWithData:packedData encoding:NSUTF8StringEncoding] autorelease]];
int messageType, channel, data1, data2;
[scanner scanInt:&messageType];
[scanner scanInt:&channel];
[scanner scanInt:&data1];
[scanner scanInt:&data2];
答案 1 :(得分:2)
这是我放在一起的3字节解决方案。
char theBytes[] = {message_type * 16 + channel, data1, data2};
NSData *packedData = [NSData dataWithBytes:&theBytes length:sizeof(theBytes)];
char theBytesRecovered[3];
[packedData getBytes:theBytesRecovered];
int messageTypeAgain = (int)theBytesRecovered[0]/16;
int channelAgain = (int)theBytesRecovered[0] % 16;
int data1Again = (int)theBytesRecovered[1];
int data2Again = (int)theBytesRecovered[2];
NSLog(@"packed %d %d %d %d", messageTypeAgain, channelAgain, data1Again, data2Again);
并且在导线的另一侧,这很容易拾取,因为每个字节都是一个字节。我刚刚在iOS端和Java端完成了这个尝试,并且两者都没有问题。 endian-ness没有问题,因为每个整数都适合一个字节(或者一个字节中的两个,在一种情况下)。
答案 2 :(得分:0)
你有几种选择。
因为看起来你想要在NSData表示中连续的数据集......
您将要创建一个压缩结构,并将数据作为预定义的字节顺序传递给NSData调用(因此两端都知道如何取消归档数据glob)。
/* pack this struct's ivars and and enable -Wreorder to sanity check that the compiler does not reorder members -- i see no reason for the compiler to do this since the fields are equal size/type */
struct t_midi_message {
UInt8 message_type; /* 0-15 */
UInt8 channel; /* 0-15 */
UInt8 data1; /* 0-127 */
UInt8 data2; /* 0-127 */
};
union t_midi_message_archive {
/* members - as a union for easy endian swapping */
SInt32 glob;
t_midi_message message;
enum { ValidateSize = 1 / (4 == sizeof(t_midi_message)) };
/* nothing unusual here, although you may want a ctor which takes NSData as an argument */
t_midi_message_archive();
t_midi_message_archive(const t_midi_message&);
t_midi_message_archive(const t_midi_message_archive&);
t_midi_message_archive& operator=(const t_midi_message_archive&);
/* swap routines -- just pass @member glob to the system's endian routines */
void swapToNativeEndianFromTransferEndian();
void swapToTransferEndianFromNativeEndian();
};
void a(const t_midi_message_archive& msg) {
t_midi_message_archive copy(msg);
copy.swapToTransferEndianFromNativeEndian();
NSData * packedData([NSData dataWithBytes:©.glob length:sizeof(copy.glob)]);
assert(packedData);
t_midi_message_archive recovered;
[packedData getBytes:&recovered.glob];
recovered.swapToNativeEndianFromTransferEndian();
/* recovered may now be used safely */
}