NSArray에 c-struct를 넣는 가장 좋은 방법은 무엇입니까?
c 구조를 저장하는 일반적인 방법은 무엇입니까 NSArray
? 장점, 단점, 메모리 처리?
특히, 차이 무엇 valueWithBytes
과 valueWithPointer
- 저스틴 아래 메기에 의해 제기.
다음valueWithBytes:objCType:
은 향후 독자 를 위한 Apple의 토론 링크입니다 .
측면 적 사고와 성능에 대한 더 많은 것을보기 위해 Evgen은 C ++STL::vector
에서 사용하는 문제를 제기했습니다 .
(흥미로운 문제가 발생합니다. STL::vector
"배열의 깔끔한 처리"를 최소화 할 수있는 훨씬 더 가벼우면서도 다르지 않은 빠른 c 라이브러리가 있습니까?)
그래서 원래 질문은 ...
예를 들면 :
typedef struct _Megapoint {
float w,x,y,z;
} Megapoint;
그래서 :에서 자신의 구조를 저장하는 정상적이고 가장 좋은 관용적 방법은 NSArray
무엇이며 그 관용구에서 메모리를 어떻게 처리합니까?
특히 구조체를 저장하는 일반적인 관용구를 찾고 있습니다. 물론 새로운 작은 수업을 만들어 문제를 피할 수 있습니다. 그러나 실제로 구조체를 배열에 넣는 일반적인 관용구를 알고 싶습니다. 감사합니다.
BTW는 아마도 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를 참조 지점으로 사용하고 Jarret Hardie 덕분에 다음과 같이 저장하는 방법 CGPoints
과 비슷한 방법이 있습니다 NSArray
.
NSArray *points = [NSArray arrayWithObjects:
[NSValue valueWithCGPoint:CGPointMake(6.9, 6.9)],
[NSValue valueWithCGPoint:CGPointMake(6.9, 6.9)],
nil];
( How can I add CGPoint objects to an NSArray the easy way? )
NSValue 는 CoreGraphics 구조를 지원할뿐만 아니라 자신 만의 구조로도 사용할 수 있습니다. 클래스가 NSData
단순한 데이터 구조 보다 가볍기 때문에 그렇게하는 것이 좋습니다 .
다음과 같은 표현식을 사용하면됩니다.
[NSValue valueWithBytes:&p objCType:@encode(Megapoint)];
그리고 가치를 되찾기 위해 :
Megapoint p;
[value getValue:&p];
NSValue
경로 를 고수하는 것이 좋지만 struct
NSArray (및 Cocoa의 다른 컬렉션 개체)에 일반 'ol 데이터 유형 을 저장하고 싶다면 Core Foundation 및 수신자 부담 브리징을 사용하여 간접적으로 수행 할 수 있습니다. .
CFArrayRef
(및 변경 가능한 대응 물 CFMutableArrayRef
)은 개발자가 배열 객체를 만들 때 더 많은 유연성을 제공합니다. 지정된 이니셜 라이저의 네 번째 인수를 참조하십시오.
CFArrayRef CFArrayCreate (
CFAllocatorRef allocator,
const void **values,
CFIndex numValues,
const CFArrayCallBacks *callBacks
);
This allows you to request that the CFArrayRef
object use Core Foundation's memory management routines, none at all or even your own memory management routines.
Obligatory example:
// 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];
The above example completely ignores the issues with respect to memory management. The structure myStruct
is created on the stack and hence is destroyed when the function ends -- the array will contain a pointer to an object that is no longer there. You can work around this by using your own memory management routines -- hence why the option is provided to you -- but then you have to do the hard work of reference counting, allocating memory, deallocating it and so on.
I would not recommend this solution, but will keep it here in case it is of interest to anyone else. :-)
Using your structure as allocated on the heap (in lieu of the stack) is demonstrated here:
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];
A similar method to add c struct is to store the pointer and to de-reference the pointer as so;
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];
if you're feeling nerdy, or really have a lot of classes to create: it is occasionally useful to dynamically construct an objc class (ref: class_addIvar
). this way, you can create arbitrary objc classes from arbitrary types. you can specify field by field, or just pass the info of the struct (but that's practically replicating NSData). sometimes useful, but probably more of a 'fun fact' for most readers.
How would I apply this here?
you can call class_addIvar and add a Megapoint instance variable to a new class, or you can synthesize an objc variant of the Megapoint class at runtime (e.g., an instance variable for each field of Megapoint).
the former is equivalent to the compiled objc class:
@interface MONMegapoint { Megapoint megapoint; } @end
the latter is equivalent to the compiled objc class:
@interface MONMegapoint { float w,x,y,z; } @end
after you've added the ivars, you can add/synthesize methods.
to read the stored values on the receiving end, use your synthesized methods, object_getInstanceVariable
, or valueForKey:
(which will often convert these scalar instance variables into NSNumber or NSValue representations).
btw: all the answers you have received are useful, some are better/worse/invalid depending on the context/scenario. specific needs regarding memory, speed, ease to maintain, ease to transfer or archive, etc. will determine which is best for a given case... but there is no 'perfect' solution which is ideal in every regard. there is no 'best way to put a c-struct in an NSArray', just a 'best way to put a c-struct in an NSArray for a specific scenario, case, or set of requirements' -- which you'd have to specify.
furthermore, NSArray is a generally reusable array interface for pointer sized (or smaller) types, but there are other containers which are better suited for c-structs for many reasons (std::vector being an typical choice for c-structs).
it would be best to use the poor-man's objc serializer if you're sharing this data across multiple abis/architectures:
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;
/* ... */
...particularly if the structure can change over time (or by targeted platform). it's not as fast as other options, but it's less likely to break in some conditions (which you haven't specified as important or not).
if the serialized representation does not exit the process, then size/order/alignment of arbitrary structs should not change, and there are options which are simpler and faster.
in either event, you're already adding a ref-counted object (compared to NSData, NSValue) so... creating an objc class which holds Megapoint is the right answer in many cases.
I suggest you to use std::vector or std::list for C/C++ types, because at first it's just faster than NSArray, and at second if there will be not enough speed for you - you're always can create your own allocators for STL containers and make them even more fast. All modern mobile Game, Physics and Audio engines uses STL containers to store internal data. Just because they really fast.
If it's not for you - there is good answers from guys about NSValue - i think it's most acceptable.
Instead of trying to put c struct in a NSArray you can put them in a NSData or NSMutableData as a c array of structs. To access them you would the do
const struct MyStruct * theStruct = (const struct MyStruct*)[myData bytes];
int value = theStruct[2].integerNumber;
or to set then
struct MyStruct * theStruct = (struct MyStruct*)[myData mutableBytes];
theStruct[2].integerNumber = 10;
While using an NSValue works fine for storing structs as an Obj-C object, you cannot encode an NSValue containing a struct with NSArchiver/NSKeyedArchiver. Instead, you have to encode individual struct members...
See Apple's Archives and Serializations Programming Guide > Structures and Bit Fields
For your structure you can add an attribute objc_boxable
and use @()
syntax to put of your structure into NSValue instance without calling 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)];
An Obj C object is just a C struct with some added elements. So just create a custom class and you will have the type of C struct that an NSArray requires. Any C struct that does not have the extra cruft that an NSObject includes within its C struct will be indigestible to an NSArray.
Using NSData as a wrapper might only be storing a copy of the structs and not the original structs, if that makes a difference to you.
You can use NSObject classes other than the C-Structures to store information. And you can easily store that NSObject in to NSArray.
참고URL : https://stackoverflow.com/questions/4516991/whats-the-best-way-to-put-a-c-struct-in-an-nsarray
'IT story' 카테고리의 다른 글
웹 페이지 인쇄를위한 안전한 픽셀 너비? (0) | 2020.09.18 |
---|---|
명령 줄에서 직접 Maven 플러그인 실행을 실행하는 방법은 무엇입니까? (0) | 2020.09.18 |
Sqlite 또는 MySql? (0) | 2020.09.18 |
[:]은 무슨 뜻인가요? (0) | 2020.09.18 |
C에서 nan과 inf를 사용하는 방법? (0) | 2020.09.18 |