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!
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:
[ClassName classMethod]
[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:
.