类方法如何访问实例方法?

时间:2013-07-19 06:11:55

标签: objective-c

我来自Actionscript Background。在Actionscript类中,Method只能访问Class Methods和Class属性。

但在目标C中,

  1. 类方法gameResultAll如何访问实例方法initFromPlist

    +(NSMutableArray *)gameResultAll://Class Method
    
    -(id)initFromPlist:(id)plist;//Instance Method
    
    NSMutableArray *gameResults = [GameResult gameResultAll]; // (returns GameResult array)
    
  2. 为什么调用[self init]方法而不是[super init]来从类方法创建实例。

  3. 提前致谢。

    #import "GameResult.h"
    
    @implementation GameResult
    
    #define GAME_RESULT_KEY @"gameresult_key"
    #define SCORE_KEY @"score"
    
    +(NSMutableArray *)gameResultAll
    {
    
        NSMutableArray *resultArray = [[NSMutableArray alloc] init];
        for (id plist in [[[[NSUserDefaults standardUserDefaults] dictionaryForKey:GAME_RESULT_KEY] mutableCopy] allValues]) 
        {
            GameResult *gameResult = [[GameResult alloc] initFromPlist:plist];
            [resultArray addObject:gameResult];
        }
        return  resultArray;
    }
    
    //Designated initialiser
    -(id)initFromPlist:(id)plist
    {
    
        self = [self init];
        if(self)
        {
           if([plist isKindOfClass:[NSDictionary class]])
           {
               NSDictionary *resultDictionary = (NSDictionary*)plist;
               _score = (int)resultDictionary[SCORE_KEY];
           }
        }
        return  self;
    }
    

2 个答案:

答案 0 :(得分:2)

  

在Actionscript中,Class Method只能访问Class Methods和Class属性。

在Objective-C中也没有什么不同(因为没有别的意义),所以:

  

类方法GameResultAll如何访问实例方法initFromPlist

仅通过有效的实例。

  

为什么调用[self init]方法而不是[self super]来从类方法创建实例。

因为后者是语法错误,也许?阅读基本的Objective-C教程。

答案 1 :(得分:2)

你问:

  

类方法gameResultAll如何访问实例方法initFromPlist

它可以访问该方法,因为您使用了alloc方法,该方法创建了GameResult的实例。现在您有了一个实例,您可以将实例方法与此实例结合使用。

顺便说一下,这是一个非常常见的模式,一个“方便”类方法,它分配一个对象的实例(带alloc)并初始化对象(使用init或一些排列那)。或者,在这种情况下,它可以创建这些对象的数组。

然后你继续问:

  

为什么调用[self init]方法而不是[super init]来从类方法创建实例。

我可以理解这种困惑,但这两者的行为有一个重要但微妙的区别。

想象一下这种情况:

  • 在将来某个日期,您将GameResult作为子类,例如ArcadeGameResult;

  • 您为init实现了ArcadeGameResult方法,该方法初始化了此子类特有的一些属性;以及

  • 您碰巧初始化ArcadeGameResult实例,如下所示:

    ArcadeGameResult *agr = [[ArcadeGameResult alloc] initFromPlist:plist];
    

由于initFromPlist使用[self init],这意味着initFromPlist GameResult方法将最终调用对象的init方法(在这个例子中,实际上是一个ArcadeGameResult对象)。但如果initFromPlist中的GameResult改为[super init],则会调用ArcadeGameResult的{​​{1}}方法,因此{{ 1}}如果与子类一起使用会有问题。

底线,除非您调用的方法是完全相同的方法签名,否则调用init再现而不是initFromPlist再现更安全。如果您决定在将来继承子类,它会更灵活一些。


律师有一个必然结果。从实例方法调用类方法时,应该引用self而不是类名。所以,想象一下你的super类有一个类方法:

[self class]

如果你有一些GameResult实例方法可以利用这个方法,你可能会想写:

+ (void)someClassMethod
{
    // do something
}

但这不是一个好主意。您将改为使用以下内容:

GameResult

它们看起来非常相似,但后者允许您在子类中实现- (void)someInstanceMethod { // do some stuff [GameResult someClassMethod]; } ,并且此实例方法仍然有效。如果使用前一个构造,则- (void)someInstanceMethod { // do some stuff [[self class] someClassMethod]; } 不会调用子类化方法。

这些是微妙的问题,可能对您当前的代码示例并不重要。但希望它能说明在这种情况下someClassMethodsomeInstanceMethod的选择。