Objective-C中的工厂方法

时间:2014-05-25 22:22:52

标签: objective-c objective-c-blocks

我是这样的类工厂,

@implementation Universe {
    NSString *foo;
}

+ (instancetype)universeWithMeaning:(NSString *)meaning
{
    return [[self alloc] initUniverseWithMeaning:meaning];
}

- (id)initUniverseWithMeaning:(NSString *)meaning
{
    if (self = [super init]) {
        foo = meaning;
    }
    return self;
}

- (void)showMeaning
{
    NSLog(@"%@", foo);
}

@end

创建像这样的对象,

Universe *universe = [Universe universeWithMeaning:@"42"];
[universe showMeaning];     // Prints 42

这很好用,但initUniverseWithMeaning:的方法签名与universeWithMeaning:的方法签名相同,只不过它是一个允许它将实例变量保存到创建对象的实例方法。

有没有办法解决这个问题,而无需实现initUniverseWithMeaning:实例方法?

我知道必须在实例方法中才能访问实例变量,所以我一直在试验块。我的想法是将包含实例变量赋值的块传递给类方法,该方法将以某种方式在实例上下文中执行它。

实施,

@implementation Cat {
    NSString *lives;
}

+ (Cat *)newCat:(void(^)(void))cat
{
    cat();    // **Problem 1**
}

- (void)showLives
{
    NSLog(@"%@", lives);
}

@end

用法,

Cat *cat = [Cat newCat:^void (void) {
    self.lives = 9;    // **Problem 2**
}];

[cat showLives];       // I'd like this to print 9

问题1:如何创建Cat对象并在其中执行cat()?

问题2:如何让self引用块执行环境中的对象?

无论如何,这比其他任何事情更具好奇心,只有在保存我写alloc时才会有用(我只需要在initUniverseWithMeaning:中加入{{1}}的方法原型。 h文件。)

2 个答案:

答案 0 :(得分:2)

对于您的问题1和2,您可以试试这个

@interface Cat ()
@property (strong) NSString *lives;
@end

@implementation Cat

+ (Cat *)newCat:(void(^)(Cat *me))cat
{
    Cat *newcat = [[self alloc] init];
    cat(newcat);
    return newcat;
}

- (void)showLives
{
    NSLog(@"%@", lives);
}

@end

Cat *cat = [Cat newCat:^(Cat *me) {
    me.lives = 9;
}];

[cat showLives];       // print 9

但我看不太多使用它......这不是更简单吗?

Cat *cat = [Cat new];
cat.lives = 9;
[cat showLives];

为您的真正问题

  

有没有办法解决这个问题,而无需实现initUniverseWithMeaning:instance方法?

+ (instancetype)universeWithMeaning:(NSString *)meaning
{
    Universe *universe = [[self alloc] init];
    if (universe) universe->foo = meaning;
    return universe;
}

答案 1 :(得分:1)

您发布的第一个示例是创建Objective-C工厂方法的正确方法。

Objective-C工厂方法只不过是实例级init方法的类方法包装器。一般来说,每个工厂方法都应该有一个配对的init方法,它采用相同数量和类型的参数。

fooWithBar:(NSString *)bar应与initWithBar:(NSString *)bar等配对。

当你有一个带有参数的init方法时,可能会出现异常,但是你已经为这个方法创建了一些带有默认参数的工厂方法。例如:

- (instancetype)initWithString:(NSString *)string;

+ (instancetype)fooWithString:(NSString *)string {
    return [[self alloc] initWithString:string];
}

+ (instancetype)fooWithBar {
    return [[self alloc] initWithString:@"bar"];
}

现在,您可以在方法中创建对象,然后修改它,并返回修改后的对象。

例如:

+ (instancetype)fooWithString:(NSString *)string {
    Foo *f = [[self alloc] init];
    f.str = string;
    return f;
}

但老实说,拥有initWithString:方法更好。

每个类都应该有一个指定的初始化程序,该类的每个对象都应该通过指定的初始化程序。