programing

NSA rray에 c-struct를 넣는 가장 좋은 방법은?

css3 2023. 11. 6. 21:57

NSA rray에 c-struct를 넣는 가장 좋은 방법은?

c-구조물을 저장하는 일반적인 방법은 무엇입니까?NSArray? 장점, 단점, 기억 처리?

눈에 띄는 것은, 두 사람 사이에 어떤 차이가 있습니까?valueWithBytes그리고.valueWithPointer-- 저스틴과 메기 밑에서 키웠습니다.

다음은 애플이 다음과 같이 논의하는 링크입니다.valueWithBytes:objCType:미래의 독자들을 위해...

약간의 측면적인 사고와 성능을 좀 더 보기 위해, Evgen은 다음과 같은 문제를 제기했습니다.STL::vectorC++

(그것은 흥미로운 문제를 제기합니다: fast c library가 있습니까, 다름이 아닙니다.STL::vector훨씬 더 가벼워진 덕분에 최소한의 "어레이의 tidy 처리"가 가능해졌습니다.?)

그래서 원래 질문은...

예를 들어,

typedef struct _Megapoint {
    float   w,x,y,z;
} Megapoint;

그래서: 그런 자신의 구조를 저장하는 일반적이고, 최선이며, 관용적인 방법은 무엇일까요?NSArray, 그리고 그 관용구에서 기억을 어떻게 다루나요?

구조물을 보관하는 일반적인 관용구를 특별히 찾고 있으니 참고하시기 바랍니다.물론, 새로운 작은 수업을 함으로써 그 문제를 피할 수 있습니다.하지만 실제로 구조물을 배열하는 일반적인 관용구가 어떻게 되는지 알고 싶습니다. 감사합니다.

그건 그렇고 여기 NSData 접근법이 있습니다. 아마도요?최고가 아닌...

Megapoint p;
NSArray *a = [NSArray arrayWithObjects:
    [NSData dataWithBytes:&p length:sizeof(Megapoint)],
    [NSData dataWithBytes:&p length:sizeof(Megapoint)],
    [NSData dataWithBytes:&p length:sizeof(Megapoint)],
        nil];

BTW를 참고로 하고 자렛 하디 덕분에 저장하는 방법은 다음과 같습니다.CGPoints유사한 점이 있습니다.NSArray:

NSArray *points = [NSArray arrayWithObjects:
        [NSValue valueWithCGPoint:CGPointMake(6.9, 6.9)],
        [NSValue valueWithCGPoint:CGPointMake(6.9, 6.9)],
        nil];

(CGPoint 개체를 NSRray에 쉽게 추가하려면 어떻게 해야 합니까?)

NSValue는 CoreGraphics 구조를 지원할 뿐만 아니라 자신만의 구조로도 사용할 수 있습니다.나는 그렇게 하는 것을 추천합니다, 왜냐하면 아마 수업은 무게가 더 가벼울 것이기 때문입니다.NSData단순한 데이터 구조에 적합합니다.

다음과 같은 표현을 간단히 사용합니다.

[NSValue valueWithBytes:&p objCType:@encode(Megapoint)];

가치를 다시 얻기 위해서는 다음과 같이 하십시오.

Megapoint p;
[value getValue:&p];

경로를 고수하는 것을 제안하고 싶지만, 정말로 당신이 평범한 것을 보관하고 싶다면, ol.structNSray의 데이터 유형(및 코코아의 다른 수집 개체)을 사용하면 간접적으로나마 Core Foundation과 수신자 부담 없는 브리징을 사용할 수 있습니다.

CFArrayRef (그리고 그 변하기 쉬운 상대는,CFMutableArrayRef) 어레이 객체를 생성할 때 개발자에게 더 많은 유연성을 제공합니다.지정된 이니셜라이저의 네 번째 인수 참조:

CFArrayRef CFArrayCreate (
    CFAllocatorRef allocator,
    const void **values,
    CFIndex numValues,
    const CFArrayCallBacks *callBacks
);

이것은 당신이 요청할 수 있게 해줍니다.CFArrayRef객체는 코어 파운데이션의 메모리 관리 루틴을 사용하고 전혀 사용하지 않으며 자신의 메모리 관리 루틴도 사용하지 않습니다.

의무적인 예:

// One would pass &kCFTypeArrayCallBacks (in lieu of NULL) if using CF types.
CFMutableArrayRef arrayRef = CFArrayCreateMutable(kCFAllocatorDefault, 0, NULL);
NSMutableArray *array = (NSMutableArray *)arrayRef;

struct {int member;} myStruct = {.member = 42};
// Casting to "id" to avoid compiler warning
[array addObject:(id)&myStruct];

// Hurray!
struct {int member;} *mySameStruct = [array objectAtIndex:0];

위의 예는 메모리 관리와 관련된 문제를 완전히 무시합니다.구조는myStruct스택에서 생성되므로 함수가 종료되면 삭제됩니다. 배열에는 더 이상 존재하지 않는 개체에 대한 포인터가 포함됩니다.여러분은 여러분 자신의 메모리 관리 루틴을 사용함으로써 이 문제를 해결할 수 있습니다. 그래서 여러분에게 옵션이 제공되는 이유입니다. 하지만 여러분은 참조를 세고, 메모리를 할당하고, 할당을 해제하는 등의 힘든 일을 해야 합니다.

저는 이 솔루션을 추천하지 않지만 다른 사람들이 관심을 가질 경우를 대비하여 여기에 보관할 것입니다. :-


스택 대신 힙에 할당된 구조를 사용하는 방법은 다음과 같습니다.

typedef struct {
    float w, x, y, z;
} Megapoint;

// One would pass &kCFTypeArrayCallBacks (in lieu of NULL) if using CF types.
CFMutableArrayRef arrayRef = CFArrayCreateMutable(kCFAllocatorDefault, 0, NULL);
NSMutableArray *array = (NSMutableArray *)arrayRef;

Megapoint *myPoint = malloc(sizeof(Megapoint);
myPoint->w = 42.0f;
// set ivars as desired..

// Casting to "id" to avoid compiler warning
[array addObject:(id)myPoint];

// Hurray!
Megapoint *mySamePoint = [array objectAtIndex:0];

포인터를 저장하고 포인터의 참조를 해제합니다.

typedef struct BSTNode
{
    int data;
    struct BSTNode *leftNode;
    struct BSTNode *rightNode;
}BSTNode;

BSTNode *rootNode;

//declaring a NSMutableArray
@property(nonatomic)NSMutableArray *queues;

//storing the pointer in the array
[self.queues addObject:[NSValue value:&rootNode withObjCType:@encode(BSTNode*)]];

//getting the value
BSTNode *frontNode =[[self.queues objectAtIndex:0] pointerValue];

당신이 너덜너덜하다고 느끼거나 정말로 생성해야 할 클래스가 많은 경우: 동적으로 객체 클래스를 구성하는 것이 때때로 유용합니다(ref:class_addIvar이 방법으로 임의 유형에서 임의 개체 클래스를 만들 수 있습니다.필드별로 필드를 지정하거나 구조물의 정보를 전달할 수 있습니다(NSData를 실질적으로 복제하는 것입니다).때로는 유용하지만 아마도 대부분의 독자들에게 더 '재미있는 사실'일 것입니다.

여기에 이걸 어떻게 발라요?

class_addIvar를 호출하여 새로운 클래스에 메가포인트 인스턴스 변수를 추가하거나 런타임에 메가포인트 클래스의 objc 변형(예: 메가포인트의 각 필드에 대한 인스턴스 변수)을 합성할 수 있습니다.

전자는 컴파일된 objc 클래스와 동등합니다.

@interface MONMegapoint { Megapoint megapoint; } @end

후자는 컴파일된 objc 클래스와 동등합니다.

@interface MONMegapoint { float w,x,y,z; } @end

ivar를 추가한 후 메서드를 추가/synthe할 수 있습니다.

수신단에 저장된 값을 판독하려면 합성된 방법을 사용합니다.object_getInstanceVariable, 아니면valueForKey:(이는 종종 이러한 스칼라 인스턴스 변수를 NSNumber 또는 NSValue 표현으로 변환합니다.)

그건 그렇고: 여러분이 받은 모든 답변은 유용하고, 몇몇은 상황에 따라 더 나은/worse/invalid한/scenario한 답변도 있습니다.메모리, 속도, 유지보수의 용이성, 전송 또는 보관의 용이성 등과 관련된 구체적인 요구는 주어진 경우에 어떤 것이 최선인지를 결정할 것입니다...하지만 모든 면에서 이상적인 '완벽한' 해결책은 없습니다.NSArray에 c-struct를 넣는 가장 좋은 방법은 없으며, 단지 '특정 시나리오, 사례 또는 요구사항 집합에 대해 NSArray에 c-struct를 넣는 가장 좋은 방법'만 있을 뿐입니다.

또한 NSRray는 포인터 크기(또는 그보다 작은) 유형에 대해 일반적으로 재사용 가능한 어레이 인터페이스이지만 여러 가지 이유로 c-struct에 더 적합한 다른 컨테이너도 있습니다(std::vector는 c-struct의 일반적인 선택입니다).

여러 abis/architecture에서 이 데이터를 공유하는 경우 poor-man's objc serializer를 사용하는 것이 가장 좋습니다.

Megapoint mpt = /* ... */;
NSMutableDictionary * d = [NSMutableDictionary new];
assert(d);

/* optional, for your runtime/deserialization sanity-checks */
[d setValue:@"Megapoint" forKey:@"Type-Identifier"];

[d setValue:[NSNumber numberWithFloat:mpt.w] forKey:@"w"];
[d setValue:[NSNumber numberWithFloat:mpt.x] forKey:@"x"];
[d setValue:[NSNumber numberWithFloat:mpt.y] forKey:@"y"];
[d setValue:[NSNumber numberWithFloat:mpt.z] forKey:@"z"];

NSArray *a = [NSArray arrayWithObject:d];
[d release], d = 0;
/* ... */

...특히 시간이 지남에 따라(또는 목표 플랫폼에 따라) 구조가 변경될 수 있는 경우.다른 옵션만큼 빠르지는 않지만 일부 조건(중요하거나 중요하지 않은 조건)에서 오류가 발생할 가능성이 적습니다.

직렬 표현이 프로세스를 종료하지 않는 경우 임의 구조의 크기/순서/정렬이 변경되지 않아야 하며, 보다 단순하고 빠른 옵션이 있습니다.

어느 경우든, NSData, NSValue와 비교하여 계산된 개체를 이미 추가하고 있으므로...많은 경우 메가포인트를 보유한 objc 클래스를 만드는 것이 정답입니다.

C/C++ 유형의 경우 std::vector 또는 std::list를 사용하는 것이 좋습니다. 처음에는 NSRray보다 빠르기 때문이고, 나중에는 속도가 부족할 경우 언제든지 STL 컨테이너에 대한 할당자를 직접 생성하여 훨씬 더 빠르게 만들 수 있기 때문입니다.모든 최신 모바일 게임, 물리학 및 오디오 엔진은 내부 데이터를 저장하기 위해 STL 컨테이너를 사용합니다.그들이 정말 빠르다는 이유로.

NSValue에 대한 남자들의 좋은 답변이 있는 것처럼, 당신을 위한 것이 아니라면 가장 받아들일 만하다고 생각합니다.

구조를 NSRray에 넣으려고 하는 대신 구조의 배열로 NSData 또는 NSMutableData에 넣을 수 있습니다.액세스하려면 다음 작업을 수행해야 합니다.

const struct MyStruct    * theStruct = (const struct MyStruct*)[myData bytes];
int                      value = theStruct[2].integerNumber;

또는 설정할 때

struct MyStruct    * theStruct = (struct MyStruct*)[myData mutableBytes];
theStruct[2].integerNumber = 10;

NSValue를 사용하면 구조물을 Obj-C 개체로 저장할 수 있지만 NSrchiver/NSKeyedArchiver가 있는 구조물이 포함된 NSValue를 인코딩할 수 없습니다.대신 개별 구조 부재를 인코딩해야 합니다...

Apple의 Archives and Serializations Programming Guide > Structures and Bit 필드 보기

구조에 대해 속성을 추가할 수 있습니다. objc_boxable사용.@()호출하지 않고 NSValue 인스턴스에 구조를 넣을 구문valueWithBytes:objCType::

typedef struct __attribute__((objc_boxable)) _Megapoint {
    float   w,x,y,z;
} Megapoint;

NSMutableArray<NSValue*>* points = [[NSMutableArray alloc] initWithCapacity:10];
for (int i = 0; i < 10; i+= 1) {
    Megapoint mp1 = {i + 1.0, i + 2.0, i + 3.0, i + 4.0};
    [points addObject:@(mp1)];//@(mp1) creates NSValue*
}

Megapoint unarchivedPoint;
[[points lastObject] getValue:&unarchivedPoint];
//or
// [[points lastObject] getValue:&unarchivedPoint size:sizeof(Megapoint)];

사용하는 대신NSArray, 다른 용기가 있습니다.NSPointerArray포인터 유형:

Megapoint point = ...;
NSPointerArray *arr = [NSPointerArray weakObjectsPointerArray];

[arr addPointer:&point];

for (NSUInteger i = 0; i < arr.count; i++) {
    Megapoint *ppoint = [arr pointerAtIndex:i];
    NSLog(@"%p", ppoint);
}

그 물체의 기억을 유지하는 것은 당신 자신의 위험입니다.

Obj C 객체는 일부 요소가 추가된 C 구조일 뿐입니다.따라서 사용자 지정 클래스를 생성하면 NSRray에 필요한 C 구조의 유형을 갖게 됩니다.NSO 개체가 C 구조 내에 포함하는 여분의 크래프트가 없는 C 구조는 NSArray에서 소화할 수 없습니다.

NSData를 래퍼로 사용하는 것은 원래의 구조물이 아닌 구조물의 복사본만 저장하는 것일 수 있습니다.

C-Structures 이외의 NSObject 클래스를 사용하여 정보를 저장할 수 있습니다.NSO 개체를 NSRray에 쉽게 저장할 수 있습니다.

언급URL : https://stackoverflow.com/questions/4516991/whats-the-best-way-to-put-a-c-struct-in-an-nsarray