Search code examples
objective-cclass-method

Objective-C Class Method


My header class looks like:

#import "Card.h"

@interface PlayingCard : Card

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

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

@end

And my implementation:

@implementation PlayingCard

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

+ (NSArray *) rankStrings
{
    return @[@"?", @"1", @"2", @"3", @"4"];
}

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

- (NSString *)suit
{
    return _suit ? _suit : @"?"; // if suit !nil return suit, else return ? string.
}

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


@end

So I understand that any method with a + means it's a Class method.

My question is, why must I use [PlayingCard classMethod] e.g. [PlayingCard validSuits] in the setSuit method whereas I can use [self classMethod] e.g. [self rankStrings] in the maxRank method?

I'm assuming it's something to do with the maxRank method being a class method whereas setSuit isn't. But could it be because setSuit is a setter?

I really don't know, I can't visualise what's going on here. I've only just started my foray into Objective-C and am coming from a Java background.

I have realised I can substitute PlayingCard in for self in the maxRank method without any error messages, however substituting self in for PlayingCard in the setSuit method gives me an error saying

No visible @interface for 'PlayingCard' declares the selector for 'validSuits'

Any explanation as to why this is the case and what's going on would be great. Thanks!


Solution

  • The meaning of self in methods

    Every Objective-C method receives an implicit self argument. Instance methods receive the instance, while class methods receive the class object (remember: classes are objects).

    If you want to send a class method, the compiler lets you use two types of syntax:

    1. [ClassName classMethod]
    2. [classObjectPtr classMethod]

    The first syntax is used in [PlayingCard maxRank]. Here, the target is (explicitly) the PlayingCard class.

    A class method already has a class object as a target for sending class methods: the self argument. So they can use [self classMethod] to send other class methods.

    Why sending a message to self in class methods?

    The advantage of the latter is that the class is not explicitly named. This makes it possible to override class methods in subclasses and call them from base classes.

    You basically get the same dynamic method dispatch as with instance methods. This is actually a nice feature of Objective-C not present in Java or C++.

    Instance methods would use the dynamic version by accessing their class and sending the message to that:

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

    Now an imaginary subclass of PlayingCard could override the class method validSuits and implicitly alter the behavior of setSuit:.