문제

저는 Objective-C로 작업 중이고 NSArray의 int를 NSMutableData에 추가해야 합니다(연결을 통해 데이터를 보낼 준비를 하고 있습니다).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)];
도움이 되었습니까?

해결책

Numero는 숫자 값이 아니며 숫자 값을 재판하는 물체에 대한 포인터입니다. 당신이하려고하는 것은 작동하지 않으며, 크기는 항상 포인터 (32 비트 플랫폼의 경우 4, 64 비트의 경우 8)와 동일하며, 숫자와 달리 데이터에 대한 일부 쓰레기 포인터 값을 추가합니다.

당신이 그것을 피하려고하더라도, 당신은 nsnumber를 뒷받침하는 바이트에 직접 액세스 할 수없고 그것이 작동하기를 기대할 수 없습니다. 진행중인 것은 내부 구현 세부 사항이며, 릴리스마다 다를 수 있으며, 동일한 릴리스의 다른 구성 (32 비트 대 64 비트, iPhone 대 Mac OS X, ARM vs i386 vs 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

수신 측면에서 정수를 잡고 NUMBERWITHINTEGER로 NSNUMBER를 재현합니다. NTOHL을 사용하여 기본 호스트 형식으로 변환 한 후.

최소한의 표현 등을 보내려고하는 경우 좀 더 많은 작업이 필요할 수 있습니다.

다른 옵션은 NSCoder 서브 클래스를 사용하고 NSNUMBER에 코더를 사용하여 스스로를 인코딩하도록 지시하는 것입니다. 왜냐하면 플랫폼 중립이되기 때문입니다.

다른 팁

먼저, NSNumber *numero는 "NSNumber 유형에 대한 포인터"이고 NSNumber 유형은 Objective-C 객체입니다.일반적으로, 문서에 특별히 언급되지 않는 한, 객체 지향 프로그래밍의 경험 법칙은 "내부 상태를 나타내는 객체가 어떻게 객체 구현에 비공개이며, 검은 색으로 취급되어야하는지에 대한 내부 세부 사항입니다. 상자." 다시 말하지만, 문서에서 달리 할 수 ​​있다고 말하지 않는 한, nsnumber가 C Primitive 유형의 C를 사용하고 있다고 가정 할 수 없습니다. int 저장하기 위해 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바이트입니다. numero (Obj-C의 객체에 대해 항상 isa, 객체 클래스).나는 당신이 "원했던" 것이 인스턴스화된 객체(numero의 값)에 대한 포인터를 복사하는 것이라고 생각합니다. 이 경우에는 다음을 사용해야 했습니다. &numero.이는 GC를 버퍼로 사용하는 경우 문제가 됩니다. NSMutableData 스캔되지 않습니다(즉, GC 시스템은 더 이상 객체를 "인식"하지 않고 이를 회수하지 않으므로 나중에 임의의 충돌이 발생할 가능성이 높습니다.)

인스턴스화된 항목에 포인터를 놓는 경우에도 NSNumber 반대하다 data, 해당 포인터는 이를 생성한 프로세스의 컨텍스트에서만 의미를 갖습니다.해당 개체에 대한 포인터는 해당 포인터를 다른 컴퓨터로 보내는 경우 훨씬 덜 의미가 있습니다. 수신 컴퓨터는 포인터가 보내는 컴퓨터에서 가리키는 메모리를 읽을 수 있는 (실질적이고 사소한) 방법이 없습니다.

프로세스의 이 부분에 문제가 있는 것 같으므로, 반드시 겪게 되는 매우 어려운 구현 버그를 디버깅하는 데 드는 수많은 시간을 절약할 수 있는 권장 사항을 제시하겠습니다.

머신 간에 원시 바이너리 데이터를 전송하려는 이러한 전체 아이디어를 버리고 머신 간에 간단한 ASCII/UTF-8 형식의 정보만 전송하세요.

이것이 얼마나 느리거나 비효율적이라고 생각한다면 먼저 단순화된 ASCII/UTF-8 문자열화 버전을 사용하여 모든 것을 가져오는 것이 좋습니다.저를 믿으세요. 원시 바이너리 데이터를 디버깅하는 것은 재미가 없습니다. NSLog(@"I got: %@", dataString) 피할 수 없는 문제를 디버깅할 때 금만큼의 가치가 있습니다.그런 다음 모든 것이 굳어지고 교환해야 하는 항목을 더 이상 변경할 필요가 없다고 확신하면 해당 구현을 바이너리 전용 버전으로 "포팅"(더 나은 단어가 없음)합니다. 만약에, 그리고 만약에, Shark.app을 사용한 프로파일링을 통해 이를 문제 영역으로 식별합니다.참고로 요즘은 scp 기계 간 파일을 전송하고 전송으로 기가비트 링크를 포화시킵니다. scp 아마도 80MB/초를 전송하는 동안 데이터를 압축하고 암호화하려면 이 간단한 문자열화보다 바이트당 약 5,000배 더 많은 처리를 수행해야 할 것입니다.그러나 최신 하드웨어에서는 이 정도가 메뉴 표시줄에서 실행되는 CPU 측정기를 움직이기에는 거의 충분하지 않습니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top