从 Objective C 中的 属性 名称自动生成 _instanceVariable
Auto generation of _instanceVariable from property name in Objective C
我是 Objective C 的新手,我正在使用 Stanford CS193P course for the basics. In the first lecture,据我了解,每当我在头文件中声明一个 属性 时,Objective C 为 属性 自动生成 setter 和 getter,其中 getter 名称与 属性 名称相同。教授还提到了 @synthesize
关键字,它用于将某些东西设置为 instance variable
名称,例如 @synthesize card = _card
。
所以现在,也可以直接使用 _card
对 属性 进行任何更改。
然而,他多次提到所有这一切都发生在幕后,none 这在实现文件中出现在我们面前。
如果是这样,那么在下面的代码中:
//
// 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
。
这是为您完成的,除非您自己明确地实现了 setter 和 getter 方法。我认为您还应该看到一个编译警告,表明这发生在 属性 定义上。
当您指定 属性 时,您正在定义线程和内存管理,但如果您随后实现访问器方法,则无法保证您确实遵循了这些规则。在这种情况下,您实际上可能同时使用了一些其他内存,因此您需要告诉编译器您希望它做什么。
您已经定义了自己的 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
语句中,您还会发现使用 class 的代码也更容易,例如:
if (cardsOnTable[i].suit == _cardsInHand[j].suit) {
points++;
}
一旦您覆盖了 getter 方法,所有的魔力都消失了。当你覆盖它时,你必须手动声明支持 属性 的 ivar 或使用 @synthesis ,它基本上做同样的事情。您仍然可以定义自定义 setter,但发现 ivar 仍然存在。
我是 Objective C 的新手,我正在使用 Stanford CS193P course for the basics. In the first lecture,据我了解,每当我在头文件中声明一个 属性 时,Objective C 为 属性 自动生成 setter 和 getter,其中 getter 名称与 属性 名称相同。教授还提到了 @synthesize
关键字,它用于将某些东西设置为 instance variable
名称,例如 @synthesize card = _card
。
所以现在,也可以直接使用 _card
对 属性 进行任何更改。
然而,他多次提到所有这一切都发生在幕后,none 这在实现文件中出现在我们面前。
如果是这样,那么在下面的代码中:
//
// 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
。
这是为您完成的,除非您自己明确地实现了 setter 和 getter 方法。我认为您还应该看到一个编译警告,表明这发生在 属性 定义上。
当您指定 属性 时,您正在定义线程和内存管理,但如果您随后实现访问器方法,则无法保证您确实遵循了这些规则。在这种情况下,您实际上可能同时使用了一些其他内存,因此您需要告诉编译器您希望它做什么。
您已经定义了自己的 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
语句中,您还会发现使用 class 的代码也更容易,例如:
if (cardsOnTable[i].suit == _cardsInHand[j].suit) {
points++;
}
一旦您覆盖了 getter 方法,所有的魔力都消失了。当你覆盖它时,你必须手动声明支持 属性 的 ivar 或使用 @synthesis ,它基本上做同样的事情。您仍然可以定义自定义 setter,但发现 ivar 仍然存在。