3

我实现了旧的 init-as-a-factory 模式,但在一种特殊情况下(但不是其他情况!)我从分析器收到有关内存泄漏的警告。事实上,查看Cocoa 内存管理策略规则,它 is alloc, notinit可以返回 +1-retain-count 对象。

所以看起来:

  1. 严格来说,释放self和返回一个新对象是违反规则的。init
  2. Internet 上的许多地方都在推广这种技术,并且由于 alloc/init 的串联性质,这确实有效。
  3. 分析仪有时会抱怨这一点,有时不会。

所以……我们一直都做错了吗?

4

3 回答 3

2

你可以init像这样实现,它应该释放以平衡来自调用self的保留计数。alloc

- (id)initWithSomething:(id)something
{
    [self release]; // don't need this line for ARC
    self = nil;
    return [[PrivateSubClass alloc] initWithSomething:something];
}

并且它经常init作为工厂方法来实现。例如NSArray, NSDictionary,NSString

于 2013-06-09T23:05:24.973 回答
0

在不知道导致分析器行为的代码是什么的情况下,很难判断,但作为一般规则,这里有几种编译器友好的方法来定义初始化/工厂方法。

经典分配/初始化

- (instancetype)initWithParameter:(id)parameter {
    if(self = [super init]) {
       _parameter = parameter; 
    }
    return self;
}

用法

MyCustomClass * myInstance = [[MyCustomClass alloc] initWithParameter:foo];

这将产生一个具有 +1 保留计数的实例。在 ARC 下,这将自动得到妥善管理,因为它遵循 NARC 规则(新建、分配、保留、复制)。出于同样的原因,在 ARC 之前的环境中,它必须由客户端显式发布。

自定义工厂方法

+ (instancetype)canIHazInstanceWithParameter:(id)parameter {
    return [[self alloc] initWithParameter:parameter]; // assuming -initWithParameter: defined
}

弧前

+ (instancetype)canIHazInstanceWithParameter:(id)parameter {
    return [[[self alloc] initWithParameter:parameter] autorelease]; // assuming -initWithParameter: defined
}

用法

MyCustomClass * myInstance = [MyCustomClass canIHazInstanceWithParameter:foo];

在 ARC 和 pre-ARC 中,该方法都返回一个自动释放的实例(这在 ARC 前的实现中显然更加明确),它不必由客户端管理。

评论

  • 您可能已经注意到instancetype关键字。这是 Clang 引入的一个方便的语言扩展,在实现你自己的构造函数/工厂方法时,它把编译器变成了一个亲爱的朋友。我写了一篇关于这个主题的文章,可能与你有关。

  • 工厂方法是否比方法更可取init是有争议的。从客户端的角度来看,它在 ARC 下没有太大区别,只要您仔细遵循命名约定,即使我个人倾向于在接口中公开工厂方法,而init仅在内部实现自定义方法(就像我在上面的示例中所做的那样) . 这更多的是风格问题,而不是实际的实际问题。

于 2013-06-10T00:28:27.350 回答
0

正如gaige所说,如果您发布一段代码而不是解释,它会更加清晰。

无论如何,您可以将您的工厂移动到类方法中,这样您就不会遇到这样的问题了。我的意思是这样的:

MyClass* instance = [MyClass instanceWithParameters:params];

@interface MyClass
+ (MyClass*) instanceWithParameters:(ParamType)params;
@end
于 2013-06-09T14:02:03.183 回答