【问题标题】:Auto generation of _instanceVariable from property name in Objective C从Objective C中的属性名称自动生成_instanceVariable
【发布时间】:2015-12-16 10:09:14
【问题描述】:

我是 Objective C 的新手,我正在使用斯坦福 CS193P 课程来学习基础知识。在first lecture 中,据我了解,每当我在头文件中声明一个属性时,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

【问题讨论】:

  • 问得很好。

标签: objective-c properties instance-variables


【解决方案1】:

它是为您完成的,除非您自己显式地实现 setter 和 getter 方法。我认为您还应该看到在属性定义上发生这种情况的编译警告。

当您指定一个属性时,您正在定义线程和内存管理,但是如果您随后实现访问器方法,则无法保证您确实遵循这些规则。在这种情况下,您实际上可能同时使用了其他一些内存,因此您需要告诉编译器您想要它做什么。

【讨论】:

    【解决方案2】:

    您已经定义了自己的 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 语句中,你也会发现使用这个类的代码也更容易,例如:

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

    【讨论】:

      【解决方案3】:

      一旦你重写了一个 getter 方法,所有的魔法都消失了。当您覆盖它时,您必须手动声明支持该属性的 ivar 或使用基本上相同的 @synthesis。您仍然可以定义自定义设置器并发现 ivar 仍然存在。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-01-08
        • 2017-12-31
        • 2014-12-22
        相关资源
        最近更新 更多