11

Game Centerを使用してネットワーク経由でオブジェクトを送信するために、オブジェクトに追加する必要があるNSValue( KVC を介して取得した)多数のオブジェクトがあります。明らかに、より多くの KVC ( ) のために、バックを変換する必要もあります。valueForKeyNSDataNSValueNSDatasetValue:forKey:

それぞれの正確なタイプがわからないので、およびNSValueによって提供されるインターフェースの使用に限定されます。ポインター型ではないことに注意してください。NSValueNSDataNSValue

[NSData dataWithValue:value]似たようなものがないことに驚いてい[value dataWithEncoding:]ます。しかし、おそらく私は盲目で、明らかな選択肢が見えていません。getValue:を使用して値をバッファーにコピーすることを考えましたが、それを使用してすべての可能な型と比較するvoid*以外に、バッファーの長さを決定するにはどうすればよいでしょうか?objCType

これについてどうすればよいですか?

注: NSKeyedArchiver非常に効率が悪いため、問題外です。4 バイトのフロートは 142 バイトにアーカイブされNSData、8 バイトCGPointは にアーカイブされると 260 バイトを使用しNSDataます。送信されるデータの量を最小限に抑えることは、私がやっていることにとって非常に重要です。

4

3 に答える 3

17

Martin Gordon の答えは近づいていますが、幸いなことに、objCType 文字列を手動で解析する必要はありません。それを行う関数があります: NSGetSizeAndAlignment。そこから、getValue: から取得した値のサイズ/長さを取得します。この質問は私を解決策に導きました。

最終的に、NSNumber または NSValue オブジェクトから NSData を作成できる NSData のカテゴリを作成しました。

@interface NSData (GameKitCategory)
+(NSData*) dataWithValue:(NSValue*)value;
+(NSData*) dataWithNumber:(NSNumber*)number;
@end

@implementation NSData (GameKitCategory)
+(NSData*) dataWithValue:(NSValue*)value
{
    NSUInteger size;
    const char* encoding = [value objCType];
    NSGetSizeAndAlignment(encoding, &size, NULL);

    void* ptr = malloc(size);
    [value getValue:ptr];
    NSData* data = [NSData dataWithBytes:ptr length:size];
    free(ptr);

    return data;
}

+(NSData*) dataWithNumber:(NSNumber*)number
{
    return [NSData dataWithValue:(NSValue*)number];
}
@end

また、この NSValue/NSNumber データの前に小さなヘッダーを追加します。これにより、データが対象とするプロパティと、データ セクションに含まれるバイト数をデコードできます。これで、値をリモート プロパティに復元できます。

于 2011-12-09T20:28:51.197 に答える
4

Since NSValue adopts the NSCoding protocol, you can use the NSCoder subclasses, NSKeyedArchiver and NSKeyedUnarchiver:

- (NSData *)dataWithValue:(NSValue *)value {
  return [NSKeyedArchiver archivedDataWithRootObject:value];
}

- (NSValue *)valueWithData:(NSData *)data {
  return (NSValue *)[NSKeyedUnarchiver unarchiveObjectWithData:data];
}

If NSKeyedArchiver and NSKeyedUnarchiver can't be used (for resulting data size issues), then you would have to find the size of the contained value yourself:

- (NSData *)dataWithValue:(NSValue *)value {
  // Can use NSGetSizeAndAlignment() instead. See LearnCocos2D's answer.
  if (type[0] == '{') {
    // Use the various NSValue struct value methods to detect the type.
  } else if (type[0] == 'c') {
    size = sizeof(char);
  } else if (type[0] == 'i') {
    size = sizeof(int);     
  } // etc for all/most of the values in the table linked below [1];

  void *bytes = malloc(size);
  [value getValue:bytes];
  return [NSData dataWithBytes:bytes length:size];
}

[1]: Objective-C Type Encodings

于 2011-12-09T15:12:52.660 に答える
0

NSCoder (NSKeyedArchiver など) を使用してデータをアーカイブし、結果の NSData を送信できます。反対側では、アーカイブを解除できます。特に NSValue で構造体やその他のアーカイブ以外のものをラップしている場合 、これにはいくつかの注意事項があります (たとえばhttp://www.cocoabuilder.com/archive/cocoa/82344-nskeyedarchiver-and-nsvalue.html )。

于 2011-12-09T15:10:10.073 に答える