私はトリッキーなことを実装しようとしています: すべてのモデル クラスには、プロパティの自動 NSCoding 実装があります。これにより、クラスにプロパティを追加および削除できるようになり、エンコード/デコードされていないものが欠落していることを心配する必要がなくなりました。(実際には、他の目的にも役立ちますが、それが主なアイデアです)。
Obj-C ランタイムのおかげで、initWithCoder を使用してアーカイブからオブジェクトを初期化するときに、プロパティのリストを調べて、ivar を値に直接割り当てようとします。さまざまな理由でセッターを通過したくないため、 setValue:forKey: は禁止されています。
面白い問題ですね。私はCポインターの微妙な点に完全に自信がないと言わなければなりません...
コードは次のとおりです。
unsigned int outCount;
objc_property_t *properties = class_copyPropertyList(class, &outCount);
for (unsigned int index = 0; index < outCount; index++) {
objc_property_t property = properties[index];
NSString *propertyNameString = [NSString stringWithUTF8String:property_getName(property)];
id value = [coder decodeObjectForKey:propertyNameString];
if (value == nil) {
continue;
}
const char *attributes = property_getAttributes(property);
NSString *typeAttribute = [[NSString stringWithUTF8String:attributes] substringWithRange:NSMakeRange(1, 1)];
const char *ivarName = [[@"_" stringByAppendingString:propertyNameString] UTF8String];
if ([typeAttribute isEqualToString:@"@"]) {
Ivar ivar = class_getInstanceVariable([self class], ivarName);
object_setIvar(self, ivar, value);
}
else if ([typeAttribute isEqualToString:@"d"]) {
double *doublePointer = getIvarPointer(self, ivarName);
*doublePointer = [value doubleValue];
}
else if ([typeAttribute isEqualToString:@"i"]) {
int *intPointer = getIvarPointer(self, ivarName);
*intPointer = [value intValue];
}
else if ([typeAttribute isEqualToString:@"c"]) {
char *charPointer = getIvarPointer(self, ivarName);
*charPointer = [value boolValue];
}
else if ([typeAttribute isEqualToString:@"Q"]) {
NSUInteger *uintegerPointer = getIvarPointer(self, ivarName);
*uintegerPointer = [value unsignedIntegerValue];
}
}
free(properties);
「getIvar」関数は次のようになります (はい、object_getInstanceVariable は ARC では許可されていないため、オブジェクト クラスで class_getInstanceVariable を使用します...):
static void* getIvarPointer(id object, char const *name)
{
Ivar ivar = class_getInstanceVariable(object_getClass(object), name);
if (!ivar) return 0;
return (unsigned char *)(__bridge void *)object + ivar_getOffset(ivar);
}
Xcode の静的アナライザーを実行すると、「ヌル ポインターの逆参照 (変数 'doublePointer' からロードされます)」という警告が表示されます。興味深いことに、同様のメッセージが int と NSUInteger に表示されましたが、現在は消えているようです... 'char' には表示されませんでした。
任意のアイデア、提案、または洞察に満ちた批判をいただければ幸いです。
コードは実際に機能します。オブジェクト クラスで double と int を自動的にデコードします。しかし、静的アナライザーがそのようなことを教えてくれる理由を理解したいと思います。