在 Big Nerd Ranch 的 iOS Programming Book(第 3 版)中,他们在 pg.194 上说……知识渊博的程序员仍然可以通过 allocWithZone: 创建 BNRItemStore 的实例,这将绕过我们偷偷摸摸的 alloc 陷阱。为了防止这种可能性,请覆盖 allocWithZone:在 BNRItemStore.m 中返回单个 BNRItemStore 实例。
+(id) allocWithZone:(NSZone *)zone
{
return [self sharedStore];
}
这句话让我感到困惑。下面的代码是否不能以某种方式证明这是错误的-
#import <Foundation/Foundation.h>
@interface BNRItemStore : NSObject
+(BNRItemStore *)sharedStore;
+(id)retrieveObject;
@end
@implementation BNRItemStore
+(BNRItemStore *)sharedStore{
static BNRItemStore *sharedStore=nil;
if (!sharedStore){
NSLog(@"Test2");
sharedStore= [[super allocWithZone:nil] init];
}
NSLog(@"sharedStore-> %@",sharedStore);
return sharedStore;
}
+(id)allocWithZone:(NSZone *)zone{
NSLog(@"Test1");
return [self sharedStore];
}
+(id)alloc{
NSLog(@"Retrieving super object");
NSLog(@"%@", [super allocWithZone:nil]);//Bypassing the subclass version of allocWithZone.
return [super allocWithZone:nil];
}
@end
int main(){
[[BNRItemStore alloc] init]; //the alloc message triggers a call to the subclass (overriding) version of +(id)alloc method
}
输出是:
- 2013-10-18 18:24:40.132 BNRItemStore[381:707] 检索超级对象
- 2013-10-18 18:24:40.134 BNRItemStore[381:707] BNRItemStore:0x7f8c72c091e0
如果子类 'alloc' 方法内的调用 [super allocWithZone:nil] 会触发对子类 allocWithZone 的调用,则控制台将记录“Test1”和“Test2”并最终导致分配静态指针。但这并没有发生。这意味着如果我们直接调用 [NSObject allocWithZone:nil] 或 [super allocWithZone:nil],消息将不会重定向到 allocWithZone 的覆盖版本(子类版本),但会直接访问执行实际操作的 NSAllocateObject() 函数分配。NSObject 中 +(id)allocWithZone 的代码必须看起来像这样——
+(id)allocWithZone:(NSZone *)zone{
return NSAllocateObject();
}
如果这个实现(NSObject 的 allocWithZone:) 包含类似 [self allocWithZone] 的东西,那么消息调度机制将包含 allocWithZone 的子类版本,这将使我们经历涉及调用 sharedStore 方法的“偷偷摸摸”陷阱。以下是我正在谈论的案例。现在,如果是这种情况,代码肯定会无限循环。显然情况并非如此。
+(id)allocWithZone:(NSZone *)zone{
if([self allocWithZone:zone]) //this would trigger a call to subclass ver. which would call sharedStore method which would then have [super allocWithZone:nil].Infinite Loop
return NSAllocateObject();
}
那么有人可以澄清这个关于这个所谓的“偷偷摸摸”陷阱的查询。陷阱是否意味着阻止任何人单独实例化。即不能使用 NSObject 的 allocWithZone,除非在 sharedStore 方法内部?请澄清..