idとdoubleの相互変換
昨日はIvarの取得を行うコードに言及したが、同じようにIvarの設定を行う関数はruntimeのソースコードを元に以下のようなコーディングにした。
Ivar _object_setInstanceVariable(id obj, const char *name, void *value) { Ivar ivar = NULL; if (obj && name) { if ((ivar = class_getInstanceVariable(object_getClass(obj), name))) { object_setIvar(obj, ivar, (__bridge id)value); } } return ivar; }
昨日書いたように、void*からidへのキャストには__bridge修飾子を追加している。
リファレンスのコードだったが、残念だがこれでは上手く行かない。テストしてみればわかるのだが、ivarにint型の値を設定した呼び出しだとテストが通るのだが、double等の実数だと想定したように値を読み書きできないのである。
IvarTest.m
: + (void)setIvarAsInt:(id)target forName:(NSString *)name forValue:(int)newValue { _object_setInstanceVariable(target, [name UTF8String], *(void**)&newValue); } + (void)setIvarAsDouble:(id)target forName:(NSString *)name forValue:(double)newValue { _object_setInstanceVariable(target, [name UTF8String], *(void**)&newValue); } // intはOK [[self class] setIvarAsInt:self forName:@"ivarInt" forValue:9999"]; STAssertTrue([self ivarInt] == 9999, nil); // doubleはNG [[self class] setIvarAsDouble:self forName:@"ivarDouble" forValue:1234.5678"]; STAssertTrue([self ivarDouble] == 1234.5678, nil);
intとdoubleで扱いが違うようだ。
とここで、Mac OS X/Lionでそれぞれの型が持つサイズをダンプしてみよう。
printf("Size of int: %lubytes\n", sizeof(int)); printf("Size of double: %lubytes\n", sizeof(double)); printf("Size of void *: %lubytes\n", sizeof(void *)); printf("Size of id: %lubytes\n", sizeof(id));
実行結果
Size of int: 4bytes Size of double: 8bytes Size of void *: 4bytes Size of id: 4bytes
なるほど。