简单的类扩展/继承澄清

时间:2014-10-31 17:54:59

标签: objective-c inheritance class-extensions

我已经写了几年Objective-C,并决定回去学习基础知识,以帮助我编写更好的代码。我试图学习所有关于实例变量,继承和类扩展的知识。我已经阅读了所有这三个,但有一件事令我难以理解。我有一个简单的应用程序,包含2个类,Person,Male(继承自Person),当然还有Main(导入Male类,因此能够访问Person和Male中的实例变量)。

代码很简单,为了空间我不会发布所有内容。 Main基本上采用这些变量并与它们一起玩。这是令我难以置信的部分:

    @interface Person : NSObject {
    float heightInMeters;
    int weightInKilos;
}

@property float heightInMeters;
@property int weightInKilos;

@end

当我删除括号和变量声明时,将其保留为:

@interface Person : NSObject

@property float heightInMeters;
@property int weightInKilos;

@end

代码仍然继承并执行得很好。

1。如果我们可以创建两个属性,那么即使在那里首先声明它们有什么意义呢?

2。为什么要创建两个实例变量AND属性以与它们对应?

3。我知道我们可以在.m中声明变量,而不是让它们对类及其子类化的所有内容都是私有的。像这样:

    @implementation Person {
    float heightInMeters;
    int weightInKilos;
    }

这有什么区别?我觉得我缺少很多基础知识。是否有一种简单的方式将这一切都放在一边?

1 个答案:

答案 0 :(得分:2)

当您声明@property时,编译器将自动合成前缀为下划线的变量,getter方法和setter方法。

@interface MyClass () 

@property(strong, nonatomic) NSString *myString;

@end

在此示例中,编译器会将变量同形化为_myString,将getter合并为

-(NSString *)myString

和setter为

-(void)setMyString:(NSString *)string

" @ property"之后的关键字(strong, nonatomic)定义属性的属性。默认情况下,strong表示所有权,这意味着在这种情况下MyClass个实例将主要负责保留/释放各自的myString个对象。 nonatomic表示不保证变量在多线程环境中始终是有效值,例如,如果与setter同时调用getter。

此外,编译器会将用于检索/设置实例变量的点语法视为对相应getter / setter方法的调用。因此,给定一个MyClass的实例

MyClass *exampleClass = [[MyClass alloc] init];

以下两个都是等同的陈述:

NSString *string1 = example.myString;   // dot syntax
NSString *string1 = [example myString]; // explicit call to the getter method

如需进一步阅读,请查看Apple的Programming with Objective-C Guide

至于你的具体问题:

1。如果我们可以创建两个属性,那么甚至首先在那里声明它们有什么意义呢?

MyClass.h文件(或大多数其他情况)declare variables explicitly as public variables实际上不是一个好主意。相反,将它们声明为属性会自动创建一个私有变量(和访问器方法),从而使OOP最佳实践更容易实现。所以宣布

是没有意义的
// MyClass.h

@interface MyClass : NSObject {
    NSString *myString // public variables not good
}

另外,由于我上面提到的点语法,如果你在self.myStringMyClass.m内部使用instanceOfMyClass.myString,公共变量myString将永远不会被触及因为合成变量名为_myString

2。为什么要创建两个实例变量AND属性来与它们对应?

见上文 - 您不需要两个实例变量,只需要一个。

3。我知道我们可以在.m中声明变量,而不是将它们保持为类以及将它子类化的所有内容。这有什么区别?我觉得我缺少很多基础知识。是否有一种简单的方式将这一切都放在一边?

如果您在@implementation文件的.m部分私下声明变量,则编译器无法通过合成getter和setter来帮助您。即使私有方法,getter和setter也可以帮助降低代码的复杂性,例如检查变量值的有效性。 (注意:你可以override accessor methods。)

// MyClass.m

@interface MyClass () // private interface

@property(nonatomic, strong) NSString *myString;

@end


@implementation MyClass {
    // no more need for private variables!
    // compiler will synthesize NSString *_myString and accessors
}

-(void)setMyString:(NSString *)string { // overwrite setter

    // no empty strings allowed in our object (for the sake of example)
    NSAssert([string length] > 0, @"String must not be empty");

    // assign private instance variable in setter
    _myString = string;
}

@end

这样,即使你继承了MyClass,子类也会继承编译器为我们合成的getter和setter方法。