Accessing class method in objective c. Using self or classname?

Weishi Z picture Weishi Z · Apr 12, 2014 · Viewed 10.6k times · Source

I am learning iOS programming and am confused by the following code regarding the use of keyword self.

From my understanding, self is like Java's this. It refers to the current instance. When I want to call a class method, the usual way should be like [PlayingCard validSuits]; But it's also OK to invade a class method on an instance, right? Like [self validSuits]; (I am in the class so self refers to an instance of PlayingCard)

But in the following code, it gives error somewhere but looks ok elsewhere.(Pointed out by 3 comments, this is within Xcode 5.1)

Am I missing anything?

(P.S. I think I am having the similar problem as here, which no one answered yet. He got the same error even using [PlayingCard validSuits]. )

//  PlayingCard.m

#import "PlayingCard.h"

@implementation PlayingCard
@synthesize suit = _suit; 

+ (NSArray *)validSuits {
    return @[@"♠︎", @"♣︎", @"♥︎", @"♦︎"];
}

+ (NSArray *)rankStrings {
    return @[@"?", @"A", @"2", @"3", @"4",@"5",@"6",@"7",@"8",@"9",@"10",@"J",@"Q",@"K"];

}

+ (NSUInteger)maxRank {
    return [[PlayingCard rankStrings] count] -1; 
          //1. [self rankStrings] works fine.** 
}


//override super class's method
- (NSString *)contents {

    NSArray *rankStrings = [PlayingCard rankStrings];  
           //2. if change rankStrings to self, then error:
           //No visible @interface for 'PlayingCard' declares the selector 'rankStrings'

    return [rankStrings[self.rank] stringByAppendingString:self.suit];
}

- (void) setSuit:(NSString *)suit {
    if ( [[PlayingCard validSuits] containsObject:suit]) {  
        //3.error when changed to [self validsuits] 
        //No visible @interface for 'PlayingCard' declares the selector 'validsuits'**
       _suit = suit;
    }

}

- (NSString *) suit {
    return _suit ? _suit : @"?";
}

@end

The header file:

//  PlayingCard.h

#import "Card.h"

@interface PlayingCard : Card

@property (nonatomic, strong) NSString *suit;
@property (nonatomic) NSUInteger rank;

+ (NSArray *) validSuits;
+ (NSUInteger) maxRank;

@end

Answer

Rich picture Rich · Apr 12, 2014

If you are calling another class method from inside a class method (of the same class) you can just use [self classMethod]. If however you are in an instance method and you need to call that classes class method you can use [[self class] classMethod]

As pointed out by @Martin R - if you subclass PlayingCard, calling self in a class method will then be that subclass and not PlayingCard.

EDIT:

For completeness you need to do:

//  PlayingCard.m

#import "PlayingCard.h"

@implementation PlayingCard
@synthesize suit = _suit; 

+ (NSArray *)validSuits {
    return @[@"♠︎", @"♣︎", @"♥︎", @"♦︎"];
}

+ (NSArray *)rankStrings {
    return @[@"?", @"A", @"2", @"3", @"4",@"5",@"6",@"7",@"8",@"9",@"10",@"J",@"Q",@"K"];

}

+ (NSUInteger)maxRank {
    return [[self rankStrings] count] -1; 
}

//override super class's method
- (NSString *)contents {

    NSArray *rankStrings = [[self class] rankStrings];  

    return [rankStrings[self.rank] stringByAppendingString:self.suit];
}

- (void) setSuit:(NSString *)suit {
    if ( [[[self class] validSuits] containsObject:suit]) {  
       _suit = suit;
    }
}

- (NSString *) suit {
    return _suit ? _suit : @"?";
}

@end