在Objective C中从属性名自动生成_instancevvariable



我是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仍然在那里。

最新更新