NSCopying
特定のコンテキスト (たとえば、テストのために内部にフックする場合) では、採用しない (実装しない)クラスのインスタンスのコピーを作成できると便利-copyWithZone:
です。これはどのように達成できますか?(注: クラスのインスタンス変数のすべてがヘッダーに表示されるわけではないため、カテゴリにプロトコルを実装するだけでは十分ではありません。)
オブジェクトの s を反復処理してみました。Ivar
(1) オブジェクト型の再帰 (または保持) の場合、(2) プリミティブ型の場合、元のインスタンス化された ivar のアドレスと作成中のコピーの取得とmemcpy
ingを試しました。ソースivarのアドレスから宛先ivarのアドレスまでのバッファ。
@interface NSObject (ADDLCopy)
- (id)addl_generateCopyDeep:(BOOL)deepCopy;
@end
@implementation NSObject (ADDLCopy)
//modified from http://stackoverflow.com/a/12265664/1052673
- (void *)addl_ivarPointerForName:(const char *)name
{
void *res = NULL;
Ivar ivar = class_getInstanceVariable(self.class, name);
if (ivar) {
res = (void *)self + ivar_getOffset(ivar);
}
return res;
}
- (id)addl_generateCopyDeep:(BOOL)deepCopy;
{
id res = [[self.class alloc] init];
unsigned int count = 0;
Ivar *ivars = class_copyIvarList(self.class, &count);
for (unsigned int i = 0; i < count; i++) {
Ivar ivar = ivars[i];
//We need to try here because of a bug with NSGetSizeAndAlignment
//which prevents bitfields from being handled properly and results
//in an exception being thrown. See this link for more discussion:
//http://lists.apple.com/archives/cocoa-dev/2008/Sep/msg00883.html
@try {
NSUInteger size = 0;
const char *encoding = ivar_getTypeEncoding(ivar);
NSGetSizeAndAlignment(encoding, &size, NULL);
char firstEncodingCharacter[2];
strncpy(firstEncodingCharacter, encoding, 1);
firstEncodingCharacter[1] = 0;
if (strcmp(firstEncodingCharacter, "@") == 0) {
if (deepCopy) {
id original = object_getIvar(self, ivar);
id copy = [original addl_generateCopyDeep:deepCopy];
object_setIvar(res, ivar, copy);
} else {
id original = object_getIvar(self, ivar);
object_setIvar(res, ivar, original);
}
} else {
const char *name = ivar_getName(ivar);
void *bytesSource = [self addl_ivarPointerForName:name];
void *bytesTarget = [res addl_ivarPointerForName:name];
memcpy(bytesTarget, bytesSource, size);
}
}
@catch (NSException *exception) {}
@finally {}
}
free(ivars);
return res;
}
@end
これはある程度機能しますが、私が認識していない問題は言うまでもなく、私が認識している明白な問題がいくつかあります。まず第一に、スーパークラスから継承された ivar をコピーしません。第二に、コレクションでは機能しません。また、のバグによりNSGetSizeAndAlignment
、ビットマスクでは機能しません。さらに、関連付けられたオブジェクトを考慮できません。
オブジェクトのインスタンス (およびそれが所有するすべてのオブジェクト) を再帰的にコピーするにはどうすればよいですか? これが完全に可能ではない場合 (void ポインターに保持および格納されている所有オブジェクトを処理することは、可能であったとしてもかなり困難に思えます)、どの程度可能でしょうか?