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
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