除了语法之外,将初始化方法编写为实例还是类方法有什么区别?

时间:2016-04-11 15:44:24

标签: objective-c syntax initialization

这是作为类方法的初始化:

+ (instancetype)imageEditorForDocument:(ImageDocument*)imageDocument
{
   ImageEditorViewController* result = nil;
   result = [[ImageEditorViewController alloc] initWithNibName:@"ImageEditorViewController"
                                                        bundle:[NSBundle mainBundle]];

   if ( result )
   {
      result.imageDocument = imageDocument;
   }
   return result;
}

这是一个初始化作为实例方法:

- (instancetype)initWithDocument:(ImageDocument *)imageDocument
{
   self = [[ImageEditorViewController alloc] initWithNibName:@"ImageEditorViewController"
                                                       bundle:[NSBundle mainBundle]];

   if( self )
   {
      self.imageDocument = imageDocument;
   }
   return self;
}

据我所知,唯一的区别是发件人在使用类初始化程序时不需要调用alloc

但还有其他原因吗?

另外,附带问题是否有一个名为初始化程序的类方法? 就像NSColor

一样
+ (NSColor *)colorWithRed:(CGFloat)red green:(CGFloat)green blue:(CGFloat)blue alpha:(CGFloat)alpha NS_AVAILABLE_MAC(10_9);

2 个答案:

答案 0 :(得分:2)

使用手动引用计数(MRC),不同之处在于工厂方法通常返回自动释放的实例,而实例方法返回调用者现在拥有的实例。

使用自动引用计数(ARC),现在可以从调用代码中隐藏该差异。

因此,唯一的区别是调用者的便利性以及类的作者编写可选工厂方法的工作量稍多。

BTW - 您的实例方法初始值设定项不正确。它应该更像是这样(不是设置cos的正确方法):

self

鉴于此,您的工厂方法应该是:

- (instancetype)initWithDocument:(ImageDocument *)imageDocument
{
   self = [super initWithNibName:@"ImageEditorViewController"
                          bundle:[NSBundle mainBundle]];

   if( self )
   {
      self.imageDocument = imageDocument;
   }

   return self;
}

答案 1 :(得分:1)

是的,存在重大差异。如果实现工厂方法(类方法),则可以选择返回对象的已存在实例(例如,从某种缓存中)而不是创建新实例。想象一下,你有一个类Country,初始化成本很高。因此,编写以下工厂方法,首先查找缓存,并且只有在找不到创建新对象的国家时才会这样:

+(instancetype) countryForCountryCode: (NSString *)countryCode 
{
    Country *country = ... // ask our "CountryCache" if we already have a cached instance of the country
    if (!country) {
        country = [[Country alloc] init];
        // Here you would also set up the new Country object, or even write a "private" initializer
        // You would also add the new instance to the cache here
    }
    return country;
}

另一方面,当你选择"传统"初始化程序在调用初始化程序之前,调用程序将始终通过alloc创建一个新实例,而您将无法返回缓存对象。

最后我记得每当我处理持久对象(如果不使用CoreData)时,我个人都会使用工厂方法。所以,如果我想从数据库中获取一个新对象,我通常会实现一个名为" load"的工厂方法。为了在数据库中实际创建一个新记录,我将实现另一个名为" create"的工厂方法。如果你在这里使用初始化程序,它会变得非常混乱。