Objective c 目标C——init是一个不适合实施工厂的地方吗?

Objective c 目标C——init是一个不适合实施工厂的地方吗?,objective-c,Objective C,我实现了旧的init-as-a-factory模式,但在一个特定的情况下(但不是其他情况!)我从分析器得到了关于内存泄漏的警告。事实上,看看规则,可以返回+1-retain-count对象的是alloc,而不是init 看来: 严格地说,释放self并从init返回新对象是违反规则的 互联网上的许多地方都在推广这项技术,由于alloc/init的串联特性,这项技术确实有效 分析人员有时对此抱怨,有时则不抱怨 所以。。。我们一直都在做错事吗?正如gaige所说,如果您发布一段代码而不是解释,就会更

我实现了旧的init-as-a-factory模式,但在一个特定的情况下(但不是其他情况!)我从分析器得到了关于内存泄漏的警告。事实上,看看规则,可以返回+1-retain-count对象的是
alloc
,而不是
init

看来:

  • 严格地说,释放
    self
    并从
    init
    返回新对象是违反规则的
  • 互联网上的许多地方都在推广这项技术,由于alloc/init的串联特性,这项技术确实有效
  • 分析人员有时对此抱怨,有时则不抱怨

  • 所以。。。我们一直都在做错事吗?

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

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

    MyClass* instance = [MyClass instanceWithParameters:params];
    
    @interface MyClass
    + (MyClass*) instanceWithParameters:(ParamType)params;
    @end
    

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

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

    如果经常将
    init
    作为工厂方法来实现,这是非常困难的。e、 g.
    NSArray
    NSDictionary
    NSString
    如果不知道是什么代码导致了分析器的行为,很难说清楚,但一般来说,这里有两种编译器友好的方法来定义init/factory方法

    经典alloc/init 用法 这将生成一个保留计数为+1的实例。在ARC下,这将自动正确管理,因为它遵循NARC规则(新建、分配、保留、复制)。 出于同样的原因,在弧前环境中,它必须由客户端显式释放

    自定义工厂方法 弧 弧前 用法 在ARC和pre-ARC中,该方法都返回一个自动释放的实例(在pre-ARC实现中,这显然更明确),而不必由客户机管理

    评论
    • 您可能已经注意到
      instancetype
      关键字。这是由Clang引入的一个便利工具,它在实现您自己的构造函数/工厂方法时将编译器变成一个好朋友。我写了关于这个主题的文章,可能与你有关

    • 工厂方法是否优于
      init
      方法仍有争议。从客户机的角度来看,如果您仔细遵循命名约定,在ARC下不会有太大区别,即使我个人倾向于在接口中公开工厂方法,而只在内部实现自定义
      init
      方法(正如我在上面的示例中所做的那样)。这与其说是一个实际问题,不如说是一个风格问题


    您能否发布导致编译器错误的代码段?正如您所指出的,这是一种常见的模式,也是大多数类集群的实现方式。此外,在init可能失败的情况下,处理失败的预弧方法是dealoc self并返回nil。类集群基于抽象工厂设计模式。静态应重命名为类。如果我正确理解OP,代码应返回
    MyClass*
    。其名称必须以
    new
    alloc
    开头,以便ARC知道它返回的对象的保留计数为+1。而
    MyClass*
    会更好;)类工厂方法不以new或alloc开头。它们通常以类名开头。例如,在NSString中使用stringWithFormat:in NSString,或在NSNumber中使用numberWithBool:in NSNumber.yeah,在使用c而不是objective-c几个月后,忘记添加*
    - (instancetype)initWithParameter:(id)parameter {
        if(self = [super init]) {
           _parameter = parameter; 
        }
        return self;
    }
    
    MyCustomClass * myInstance = [[MyCustomClass alloc] initWithParameter:foo];
    
    + (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];