2009-07-19 5 views
0

Objective-C로 작업하고 NSArray의 int를 NSMutableData에 추가해야합니다 (연결을 통해 데이터를 보낼 준비 중입니다). 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 비트 대 64 비트, iPhone 대 Mac OS X, 팔 대 i386 대 PPC). 바이트를 채우고 와이어를 통해 전송하면 실제 데이터를 가져올지라도 상대방에서 제대로 deserialize되지 않는 무언가가 생길 수 있습니다.

데이터에 넣을 수있는 정수를 인코딩 한 다음 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

내가 여전히 오류 받고 있어요 : [: 및 networkInteger는 sizeof (networkInteger) 데이터 appendBytes] : "경고 :의 인수 하나를 전달하는 'appendBytes가 : 길이 :'캐스트없이 정수의 포인터를 만든다"를 –

+0

그 마지막 줄에 있어야한다 ; "&"에주의하십시오. –

+0

그게 ... 감사합니다. 한 가지 덧붙여서, 저는 apple의 문서에서 sizeof() 앞에 "length :"라고 써야한다고 지적하고 싶었습니다. 메서드 이름의 일부입니다. 문서의 전체 예제는 다음과 같습니다. - (void) appendBytes : (const void *) 바이트 길이 : (NSUInteger) 길이 두 사람이이 사실을 보지 못했지만 아무 말하고 싶지 않았다. –

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에 추가하는 것이 인이 좀 더 명확한 것을 만든다 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은 80MB/초를 전송하는 동안이 간단한 문자열 화보다 데이터를 압축하고 암호화하는 데 바이트 당 약 5 천 배의 처리가 필요할 것입니다. 그러나 현대적인 하드웨어에서 이것은 메뉴 바에서 실행중인 CPU 미터를 움직일 정도로 간신히 충분합니다.