从 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:@"♣︎"]) { ... }

Enums 也可以用在 switch 语句中,您还会发现使用 class 的代码也更容易,例如:

if (cardsOnTable[i].suit == _cardsInHand[j].suit) {
    points++;
}

一旦您覆盖了 getter 方法,所有的魔力都消失了。当你覆盖它时,你必须手动声明支持 属性 的 ivar 或使用 @synthesis ,它基本上做同样的事情。您仍然可以定义自定义 setter,但发现 ivar 仍然存在。