2009-07-19 19 views
0

私はObjective-Cで作業しています.NSMrayからNSMutableDataにintを追加する必要があります(接続を介してデータを送信する準備をしています)。 intのNSNumberをラップしてNSMutableDataに追加すると、NSNumber intにいくつのバイトが含まれているかを知ることができますか?リンゴのドキュメントに従って、 "NSNumberは任意のCスカラー(数値)型として値を提供するNSValueのサブクラスです"ということから、sizeof()を使用することは可能でしょうか?NSNumberは、保持する番号に余分なバイトを追加しますか?

例:

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

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

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

答えて

6

NUMEROは、数値をreprestingオブジェクトへのポインタであり、数値ではありません。あなたがしようとしているものは動作しません。サイズは常にポインタ(32ビットプラットフォームの場合は4、64ビットの場合は8)と等しくなり、番号に比べてデータにガベージポインタの値が追加されます。

逆参照しようとしても、NSNumberをサポートするバイトに直接アクセスすることはできません。何が起きているのかは、リリースごとに異なる可能性があり、同じリリース(32ビットvs 64ビット、iPhone vs Mac OS X、アームvs i386対PPC)の異なる構成の間でも異なる場合があります。実際のデータにアクセスできたとしても、バイトを詰めてワイヤを介して送信すると、相手側で正しくデシリアライズされないことがあります。

あなたは本当にあなたのデータに入れて、それにNSNumbersをパックして展開することができる整数の符号化を考え出す必要があります。ネイティブホスト形式に変換するためにntohlを使用した後:あなたは、整数をつかむと、numberWithIntegerとのNSNumberを作成し直す受信側で

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 

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

など

他のオプションは、それが可能になるので、NSCoderのサブクラスを使用して、あなたのコーダを使用して自分自身をエンコードするためのNSNumberを伝えることですプラットフォーム中立ですが、あなたがやろうとしていることは過度のことかもしれません。

+0

私はまだエラーを取得しています: –

+0

「警告: 『:長さappendBytes』の渡し引数1は、キャストなしで整数からポインタを作る」その最後の行は次のようになります。 [データappendBytes:&networkIntegerのsizeof(networkInteger)] ; "&"に注意してください。 –

+0

それはそれをした...ありがとう。ちなみに、appleofのドキュメントでsizeof()の前に "length:"を置くと言っています。それはメソッド名の一部です。ドキュメントの完全な例は、このようなものです。 - (void)appendBytes:(const void *)バイトの長さ:(NSUInteger)length 私は何も言いたくはありませんでしたが、2人がこれを見なかったとき、私はそれを言及すべきだと思った。 –

2

まず、NSNumber * numeroは「NSNumber型へのポインタ」であり、NSNumber型はObjective-Cオブジェクトです。一般に、ドキュメンテーションのどこかに具体的に記載されていない限り、オブジェクト指向プログラミングの経験則は、「オブジェクトがその内部状態を表現する方法の内部的な詳細は、オブジェクト実装にとってはプライベートであり、ボックス。"もう一度、ドキュメンテーションがあなたがそうでないと言わない限り、NSNumberが与えたintの値を格納するために、Cプリミティブ型のintを使用していると仮定することはできません。

次のときappendBytes:numero「舞台裏」で何が起こっているかの大まかな近似である:これは何をNSMutableDataオブジェクトdataに追加していることであること、それはもう少し明確にし

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 *) 

numeroの最初の4バイト(Obj-Cのオブジェクトは常にisa、オブジェクトクラス)を指しています。あなたが "したい"と思うのは、ポインターをインスタンス化オブジェクト(numeroの値)にコピーすることです。その場合は、&numeroを使用してください。これは、NSMutableDataが使用しているバッファーとしてGCを使用している場合に問題になります(つまり、GCシステムはオブジェクトを「参照」しなくなり、それを再利用することはなくなります。後でランダムなクラッシュを保証します)ポイント。)

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

あなたは、プロセスのこの部分で問題を抱えているように見えるので、私はあなたがに実行するためにバインドされているいくつかの非常に困難な実装のバグをデバッグするの数え切れないほどの時間を節約する勧告を作ってみよう:

放棄マシン間で未処理のバイナリデータを送信し、単純なASCII/UTF-8形式の情報をそれらの間で送信しようとする考え方全体です。

これは、どのように遅くなるか非効率になると思うなら、最初に単純化されたASCII/UTF-8文字列化バージョンを使用してすべてのものを持ち出すことをお勧めします。あなたが不可避的な問題をデバッグしているときに生のバイナリデータをデバッグするのは楽しいことではなく、ちょうどNSLog(@"I got: %@", dataString)の能力は金の価値があります。それから、すべてが一旦ゲル化し、交換する必要があるものをそれ以上変更する必要がないと確信しているならば、バイナリのみのバージョンへの実装(より良い言葉の欠如のために)もしであり、である場合にのみ、Shark.appでプロファイリングすると問題領域として識別されます。参照のポイントとして、最近では、マシン間でファイルをscpして、転送とギガビットリンクを飽和させることができます。 scpは、おそらく、この単純な文字列化よりもデータを圧縮して暗号化するために、1バイトあたり約5千倍の処理を行う必要があり、80MB /秒を転送します。しかし、現代的なハードウェアでは、これは私のメニューバーで動いているCPUメーターを少しでも動かすだけです。

関連する問題