-1

私は Objective-C を使用しており、NSArray から NSMutableData に int を追加する必要があります (接続を介してデータを送信する準備をしています)。int を NSNumber でラップしてから NSMutableData に追加すると、NSNumber int に含まれるバイト数をどのように確認できますか? Apple のドキュメントによると、「NSNumber は任意の C スカラー (数値) 型として値を提供する NSValue のサブクラスです。」であるため、sizeof() を使用できますか?

例:

NSNumber *numero = [[NSNumber alloc] initWithInt:5];

NSMutableData *data = [[NSMutableData alloc] initWithCapacity:0];

[data appendBytes:numero length:sizeof(numero)];
4

2 に答える 2

6

numero は数値ではなく、数値を表すオブジェクトへのポインタです。サイズは常にポインター (32 ビット プラットフォームの場合は 4、64 ビット プラットフォームの場合は 8) と等しくなり、数値ではなくガベージ ポインター値をデータに追加します。

逆参照しようとしても、NSNumber をサポートするバイトに直接アクセスして、それが機能することを期待することはできません。何が起こっているかは内部実装の詳細であり、リリースごと、または同じリリースの異なる構成 (32 ビットと 64 ビット、iPhone と Mac OS X、arm と i386 と PPC) 間でさえ異なる場合があります。バイトを圧縮してネットワーク経由で送信するだけでは、実際のデータに到達できたとしても、反対側で適切に逆シリアル化されない可能性があります。

データに入れることができる整数のエンコーディングを考え出し、それに NSNumbers をパックおよびアンパックする必要があります。何かのようなもの:

NSNumber *myNumber = ... //(get a value somehow)
int32_t myInteger = [myNumber integerValue]; //Get the integerValue out of the number
int32_t networkInteger = htonl(myInteger); //Convert the integer to network endian
[data appendBytes:&networkInteger sizeof(networkInteger)]; //stuff it into the data

受信側では、ntohl を使用してネイティブ ホスト形式に変換した後、整数を取り出して numberWithInteger: で NSNumber を再作成します。

最小限の表現などを送信しようとしている場合は、もう少し作業が必要になる場合があります。

もう 1 つのオプションは、NSCoder サブクラスを使用し、コーダーを使用してそれ自体をエンコードするように NSNumber に指示することです。

于 2009-07-19T02:02:01.997 に答える
2

まず、NSNumber *numero は「NSNumber 型へのポインター」であり、NSNumber 型は Objective-C オブジェクトです。一般に、ドキュメントのどこかに特に明記されていない限り、オブジェクト指向プログラミングの経験則は、「オブジェクトがその内部状態を表すために選択する方法の内部の詳細は、オブジェクトの実装にプライベートであり、黒として扱われるべきです.箱。" 繰り返しますが、別の方法で実行できるとドキュメントに記載されていない限り、NSNumber が指定した値intを格納するためにC プリミティブ型を使用していると想定することはできません。int

以下は、「舞台裏」で何が起こっているかの大まかな概算ですappendBytes:numero

typedef struct {
  Class isa;
  double dbl;
  long long ll;
} NSNumber;

NSNumber *numero = malloc(sizeof(NSNumber));
memset(numero, 0, sizeof(NSNumber));
numero->isa = objc_getClass("NSNumber");

void *bytes = malloc(1024);

memcpy(bytes, numero, sizeof(numero)); // sizeof(numero) == sizeof(void *)

これにより、NSMutableDataオブジェクトに追加しているのは、これまでに指してdataいたものの最初の 4 バイトであることが少し明確になります (Obj-C のオブジェクトの場合、これは常にオブジェクト クラスです)。あなたが「やりたかった」ことは、ポインタをインスタンス化されたオブジェクト(numeroの値)にコピーすることだったと思います。によって使用されるバッファがスキャンされないため、GC を使用している場合、これは問題です(つまり、GC システムはオブジェクトを「認識」して再利用しなくなります。これは、後でランダムにクラッシュすることをほぼ確実に保証します)。 .)numeroisa&numeroNSMutableData

NSNumberインスタンス化されたオブジェクトへのポインターを to に置いたとしてもdata、そのポインターは、それを作成したプロセスのコンテキストでのみ意味を持つことは明らかです。そのオブジェクトへのポインターは、そのポインターを別のコンピューターに送信すると、さらに意味がなくなります。受信側のコンピューターには、送信側のコンピューターでポインターが指すメモリを読み取る (実用的で簡単な) 方法がありません。

プロセスのこの部分で問題が発生しているように見えるので、遭遇するはずの非常に困難な実装バグをデバッグする時間を数え切れないほど節約できることをお勧めします。

マシン間で生のバイナリ データを送信しようとするこの考え全体を放棄し、マシン間で単純な ASCII/UTF-8 形式の情報を送信するだけです。

これでは速度が遅くなる、または非効率になると思われる場合は、最初に簡略化された ASCII/UTF-8 文字列化バージョンを使用してすべてを起動することをお勧めします。私を信じてください。生のバイナリ データをデバッグするのは楽しいことではありませんNSLog(@"I got: %@", dataString)。避けられない問題をデバッグするときは、それだけの価値があります。次に、すべてがゲル化し、交換する必要があるものにこれ以上変更を加える必要がないと確信したら、その実装をバイナリのみのバージョンに「移植」します (適切な言葉がないため)。場合に限り、Shark.app を使用したプロファイリングで問題領域として識別されます。参考までに、最近ではscp、マシン間でファイルを転送し、転送でギガビット リンクを飽和させることができます。 scpデータを圧縮して暗号化するには、80MB/秒を転送しながら、この単純な文字列化よりもおそらく 1 バイトあたり約 5,000 倍の処理を行う必要があります。しかし、最新のハードウェアでは、これはメニュー バーで実行されている CPU メーターを動かすのにかろうじて十分です。

于 2009-07-19T03:57:18.567 に答える