很难准确判断创建了多少对象,尤其是在数组字面量的情况下。
The official docs of clang 说@[] 扩展为arrayWithObjects:count:,我怀疑它被实现为[[[self alloc] initWithObjects:objects count:count] autorelease]。
因此,此时可能会分配第二个对象,因为NSArray 是class cluster,而- [NSArray init] 的实现可能如下所示:
- (id)init
{
[self release];
self = [[__NSArrayI alloc] init];
return self;
}
为了证实我的猜想,我编写了一个小程序,在不同阶段打印各种类型的NSArray 对象的类。 请注意,为了真正确定,有必要捕获NSArray 的所有分配和初始化方法。 在我们这样做之前,我们只能推测。但无论如何,这是代码:
#import <Foundation/Foundation.h>
int main()
{
NSArray *a = [NSArray alloc];
NSLog(@"NSArray before init: %@", a.class);
a = [a init];
NSLog(@"NSArray after init: %@", a.class);
NSArray *al = @[];
NSLog(@"Array literal: %@", al.class);
NSMutableArray *ma1 = [a mutableCopy];
NSLog(@"NSMutableArray (copied): %@", ma1.class);
NSMutableArray *ma2 = [NSMutableArray alloc];
NSLog(@"NSMutableArray (manufactured) before init: %@", ma2.class);
ma2 = [ma2 init];
NSLog(@"NSMutableArray (manufactured) after init: %@", ma2.class);
return 0;
}
这是它打印的内容(NSLog() 为清楚起见已删除杂乱):
h2co3-macbook:~ h2co3$ ./quirk
NSArray before init: __NSPlaceholderArray
NSArray after init: __NSArrayI
Array literal: __NSArrayI
NSMutableArray (copied): __NSArrayM
NSMutableArray (manufactured) before init: __NSPlaceholderArray
NSMutableArray (manufactured) after init: __NSArrayM
编辑:这里还有一些涉及挂钩的代码。结果非常有趣,但这会打印很多文本,因此鼓励您编译并运行它。结果是,基本上,初始化程序确实不直接通过[NSArray init]:
#import <Foundation/Foundation.h>
#import <objc/runtime.h>
#import <objc/message.h>
void hook(Class cls, SEL sel, IMP newimp, IMP *old)
{
Method m = class_getInstanceMethod(cls, sel);
*old = method_setImplementation(m, newimp);
}
#define CLS(c) objc_getClass(#c)
#define META(c) objc_getMetaClass(#c)
IMP old_$_NSArray_$_alloc;
IMP old_$_NSMutableArray_$_alloc;
IMP old_$_NSPlaceholderArray_$_alloc;
IMP old_$_NSArrayI_$_alloc;
IMP old_$_NSArrayM_$_alloc;
IMP old_$_NSArray_$_init;
IMP old_$_NSMutableArray_$_init;
IMP old_$_NSPlaceholderArray_$_init;
IMP old_$_NSArrayI_$_init;
IMP old_$_NSArrayM_$_init;
id new_$_NSArray_$_alloc(id self, SEL _cmd)
{
printf("+ [NSArray<%p> alloc]\n", self);
return old_$_NSArray_$_alloc(self, _cmd);
}
id new_$_NSMutableArray_$_alloc(id self, SEL _cmd)
{
printf("+ [NSMutableArray<%p> alloc]\n", self);
return old_$_NSMutableArray_$_alloc(self, _cmd);
}
id new_$_NSPlaceholderArray_$_alloc(id self, SEL _cmd)
{
printf("+ [NSPlaceholderArray<%p> alloc]\n", self);
return old_$_NSPlaceholderArray_$_alloc(self, _cmd);
}
id new_$_NSArrayI_$_alloc(id self, SEL _cmd)
{
printf("+ [NSArrayI<%p> alloc]\n", self);
return old_$_NSArrayI_$_alloc(self, _cmd);
}
id new_$_NSArrayM_$_alloc(id self, SEL _cmd)
{
printf("+ [NSArrayM<%p> alloc]\n", self);
return old_$_NSArrayM_$_alloc(self, _cmd);
}
id new_$_NSArray_$_init(id self, SEL _cmd)
{
printf("- [NSArray<%p> init]\n", self);
return old_$_NSArray_$_init(self, _cmd);
}
id new_$_NSMutableArray_$_init(id self, SEL _cmd)
{
printf("- [NSMutableArray<%p> init]\n", self);
return old_$_NSMutableArray_$_init(self, _cmd);
}
id new_$_NSPlaceholderArray_$_init(id self, SEL _cmd)
{
printf("- [NSPlaceholderArray<%p> init]\n", self);
return old_$_NSPlaceholderArray_$_init(self, _cmd);
}
id new_$_NSArrayI_$_init(id self, SEL _cmd)
{
printf("- [NSArrayI<%p> init]\n", self);
return old_$_NSArrayI_$_init(self, _cmd);
}
id new_$_NSArrayM_$_init(id self, SEL _cmd)
{
printf("- [NSArrayM<%p> init]\n", self);
return old_$_NSArrayM_$_init(self, _cmd);
}
int main()
{
hook(META(NSArray), @selector(alloc), (IMP)new_$_NSArray_$_alloc, &old_$_NSArray_$_alloc);
hook(META(NSMutableArray), @selector(alloc), (IMP)new_$_NSMutableArray_$_alloc, &old_$_NSMutableArray_$_alloc);
hook(META(__NSPlaceholderArray), @selector(alloc), (IMP)new_$_NSPlaceholderArray_$_alloc, &old_$_NSPlaceholderArray_$_alloc);
hook(META(__NSArrayI), @selector(alloc), (IMP)new_$_NSArrayI_$_alloc, &old_$_NSArrayI_$_alloc);
hook(META(__NSArrayM), @selector(alloc), (IMP)new_$_NSArrayM_$_alloc, &old_$_NSArrayM_$_alloc);
hook(CLS(NSArray), @selector(init), (IMP)new_$_NSArray_$_init, &old_$_NSArray_$_init);
hook(CLS(NSMutableArray), @selector(init), (IMP)new_$_NSMutableArray_$_init, &old_$_NSMutableArray_$_init);
hook(CLS(NSPlaceholderArray), @selector(init), (IMP)new_$_NSPlaceholderArray_$_init, &old_$_NSPlaceholderArray_$_init);
hook(CLS(NSArrayI), @selector(init), (IMP)new_$_NSArrayI_$_init, &old_$_NSArrayI_$_init);
hook(CLS(NSArrayM), @selector(init), (IMP)new_$_NSArrayM_$_init, &old_$_NSArrayM_$_init);
NSArray *a = [NSArray alloc];
NSLog(@"NSArray before init: %@<%p>", a.class, a);
a = [a init];
NSLog(@"NSArray after init: %@<%p>", a.class, a);
NSArray *al = @[];
NSLog(@"Array literal: %@<%p>", al.class, al);
NSMutableArray *ma1 = [a mutableCopy];
NSLog(@"NSMutableArray (copied): %@<%p>", ma1.class, ma1);
NSMutableArray *ma2 = [NSMutableArray alloc];
NSLog(@"NSMutableArray (manufactured) before init: %@<%p>", ma2.class, ma2);
ma2 = [ma2 init];
NSLog(@"NSMutableArray (manufactured) after init: %@<%p>", ma2.class, ma2);
return 0;
}