我是Objective C的新手,正在使用斯坦福CS193P课程的基础知识。在第一节课中,根据我的理解,任何时候我在头文件中声明一个属性,Objective C都会自动为这个属性生成setter和getter, getter的名字和属性的名字是一样的。教授还提到了@synthesize
关键字,它用于设置某些东西作为instance variable
的名称,例如@synthesize card = _card
。
所以现在,可以通过直接使用_card
对属性进行任何更改。
然而,他多次提到,所有这些都发生在幕后,这些都没有出现在实现文件中。
如果是这种情况,那么在下面的代码中:
//
// PlayingCard.h
// CardGame
//
// Created by Manish Giri on 9/19/15.
// Copyright (c) 2015 Manish Giri. All rights reserved.
//
#import "Card.h"
@interface PlayingCard : Card
@property (nonatomic,strong) NSString *suit; //one of club, heart, spade, diamond
@property (nonatomic) NSUInteger rank; //numbers from 0 through 13
@end
//
// PlayingCard.m
// CardGame
//
// Created by Manish Giri on 9/19/15.
// Copyright (c) 2015 Manish Giri. All rights reserved.
//
#import "PlayingCard.h"
@implementation PlayingCard
//@synthesize suit = _suit;
//override the getter method "contents" to return the description- rank&suit of the playing card
-(NSString *) contents {
//return [NSString stringWithFormat:@"%lu %@", (unsigned long)self.rank, self.suit];
//if rank is 0 or not set, return ?
NSArray *rankStrings = @[@"?", @"1", @"2", @"3", @"4", @"5", @"6", @"7", @"8", @"9", @"10", @"11", @"12", @"13"];
return [rankStrings[self.rank] stringByAppendingString:self.suit];
}
-(NSString *) suit {
//return ? if suit is nil or not set
return _suit?_suit:@"?";
}
-(void) setSuit:(NSString *)suit {
//check the suit to be set is valid
if([@[@"♥︎", @"♦︎", @"♠︎", @"♣︎"] containsObject:suit]) {
_suit = suit;
}
}
@end
为什么我得到错误:
Use of undeclared identifier _suit. Did you mean suit?
在我得到这个错误后,我添加了@synthesize suit = _suit
行,错误被修复了,但这不是自动完成的吗?如果不是,又有什么区别呢?
教授的代码(在幻灯片中)肯定没有@synthesize
行,而仍然使用_suit
。
您已经定义了自己的getter/setter,因此已经关闭了实例变量的自动生成。您需要添加自己的实例变量:
@implementation PlayingCard () {
NSString *_suit;
}
@end
@implementation PlayingCard
...
@end
我还强烈建议您使用enum
作为套装,因为@"♥︎", @"♦︎", @"♠︎", @"♣︎"
是表示格式,对您的代码不太有用。例如:// This should be in the header file
typedef enum {
SUIT_NONE,
SUIT_HEARTS,
SUIT_DIAMONDS,
SUIT_SPADES,
SUIT_CLUBS
} Suit;
@implementation PlayingCard () {
Suit _suit;
}
@end
现在做起来更容易、更有效了:
if (_suit == SUIT_CLUBS) { ... }
比:if ([_suit isEqualToString:@"♣︎"]) { ... }
Enum
s也可以用在switch
语句中,你也会发现使用这个类更容易编写代码,例如:
if (cardsOnTable[i].suit == _cardsInHand[j].suit) {
points++;
}
这是为您完成的,除非您自己显式地实现setter和getter方法。我认为您应该还看到一个编译警告,指出这发生在属性定义上。
当您指定属性时,您定义了线程和内存管理,但是如果您实现了访问器方法,则不能保证您实际上遵循了这些规则。在这种情况下,你可能会一起使用其他内存,所以你需要告诉编译器你想让它做什么。
一旦重写getter方法,所有的魔力就消失了。当你重写它时,你必须手动声明ivar来支持这个属性,或者使用@synthesis来做同样的事情。尽管如此,你仍然可以定义自定义setter,并发现ivar仍然在那里。