NSArrayにNSValueでC構造体を格納する

NSArrayに格納するにはNSObjectのサブクラスである必要があるので
CGPointといったCの構造体はそのまま格納できない。

(追記)iPhoneではUIKit.framework/Headers/UIGeometry.hにCoreGraphic系の型を格納するNSValueのNSValueUIGeometryExtensionsカテゴリとして宣言してありました。
tonnkotsuさんありがとうございます。
まあ以下は独自型の格納の参考にしてください


プリミティブなintなどの型はNSNumberに格納してオブジェクト化するのと同様に、
NSValueを使ってこうオブジェクト化できると便利ですね。

CGPoint point = {0.0f, 1.0f};
//NSValue化
NSValue val = [NSValue valueWithCGPoint:point];
//CGPoint化
point = [val cgpointValue];
//NSArrayにいれようぜ
NSArrray *array = [NSArray arrayWithObects:[NSValue valueWithCGPoint:point], nil];

以下その方法。


構造体などの独自の型もオブジェクト化するメソッドがNSValueに存在します。


+ (NSValue *)value:(const void*)value withObjCType:(const char *)type


このメソッドはvalueをOBJCTypeとしてシリアライズします。
OBJCTypeは型コードという型を表すc文字列で、例えばint型は"i"に、float型を2つ持つNSSizeは
"{_NSSize}=ff"のように表現されます。

この型コードを生成するのが@encode()です。

以下がCGPointを保持したNSValue型を生成するコードです。

CGPoint point = {0.0f, 1.0f};
NSValue *val = [NSValue value:&point withObjCType:@encode(CGPoint)];

このNSValueからCGPointを得るには

[val getValue:&point];

のようにします。


型を頻繁にNSValueに変換する必要があるプロジェクトはこういった変換をNSValueにカテゴリで機能として追加しておくと最初の例のように使えて便利です。

@interface NSValue (CGPoint)

+ (NSValue*)valueWithCGPoint:(CGPoint)point;

- (CGPoint)cgpointValue;

@end

@implementation NSValue (CGPoint)

+ (NSValue*)valueWithCGPoint:(CGPoint)point
{
  return [NSValue value:&point withObjCType:@encode(CGPoint)];
}

- (CGPoint)cgpointValue
{
  CGPoint point;
  [self getValue:&point];
  return point;
}

@end


使い方(最初の例と同じ)

CGPoint point = {0.0f, 1.0f};
//NSValue化
NSValue val = [NSValue valueWithCGPoint:point];
//CGPoint化
point = [val cgpointValue];
//NSArrayにいれようぜ
NSArrray *array = [NSArray arrayWithObects:[NSValue valueWithCGPoint:point], nil];


(当初Objective-C2.0の本にはvalueWithPoint:(NSPoint)ってのがあったからそれにCGPointを詰め込もうと思っていたけど少なくともiPhoneのNSValueでは宣言されていませんでした)