美文网首页IOS开发ios
Objective-C中类的成员变量与属性

Objective-C中类的成员变量与属性

作者: icetime17 | 来源:发表于2015-07-09 08:42 被阅读894次

    在Objective-C的类与对象的概念中. 成员变量与属性的区别与联系一直没有搞清楚. 直到学习了[慕课网](http://imooc.com)上的这个课程[Objective-C面向对象初体验](http://imooc.com/video/7290), 才算真正有了点感觉了. 最关键的结论就是: ***类内使用成员变量{}, 类外使用属性@property***.

    ## 成员变量 ##

    ### 成员变量及其get方法. ###

    首先, 我们来看下基本的类成员变量及其使用.

    ```objective-c

    // People.h

    @interface People : NSObject

    {

    NSString *_peopleName;

    }

    @end

    ```

    在.m中不做任何事情, 然后在main.m调用_peopleName成员变量,

    (下图可以看出, 调用类的成员变量时, 使用 . 语法符号会出错, 必须***使用->来调用***):

    ![调用类的成员变量1](http://img.blog.csdn.net/20150506155223387)

    改为->, 调用p1->_peopleName的结果如下:

    ![调用类的成员变量2](http://img.blog.csdn.net/20150506155442148)

    即, 该_peopleName默认是protected, 外部调用需要设置为***@public***. 改动一下:

    ```objective-c

    // People.h

    @interface People : NSObject

    {

    @public

    NSString *_peopleName;

    }

    @end

    ```

    调用p1->_peopleName的结果如下:

    ```objective-c

    2015-05-06 15:58:41.039 memberAndProperty[2851:304100] p1._peopleName : (null)

    ```

    ### 类内部使用成员变量

    如果想在init中初始化_peopleName, 则在People.m中:

    ```objective-c

    // People.m

    - (instancetype)init

    {

    self = [super init];

    if (self) {

    _peopleName = @"people name 1";

    }

    return self;

    }

    ```

    调用p1->_peopleName的结果如下:

    ```objective-c

    2015-05-06 16:01:36.974 memberAndProperty[2895:306281] p1._peopleName : people name 1

    ```

    其他使用该成员变量的类内部方法都是类似的用法.

    ### set方法

    以上是对类成员变量_peopleName的调用, 如果想要对其附新值呢?

    ```objective-c

    // main.m

    People *p1 = [[People alloc] init];

    NSLog(@"p1._peopleName : %@", p1->_peopleName);

    p1->_peopleName = @"people name 2";

    NSLog(@"p1._peopleName : %@", p1->_peopleName);

    ```

    结果:

    ```objective-c

    2015-05-06 16:05:34.915 memberAndProperty[2931:309406] p1._peopleName : people name 1

    2015-05-06 16:05:34.916 memberAndProperty[2931:309406] p1._peopleName : people name 2

    ```

    以上可见, 将_peopleName设置为@public之后, 可在类外对其进行get/set操作, 直接调用或赋值即可.

    但***不推荐使用p1->_peopleName***这样的形式. 因为, 这样就不符合我们所说的

    ***"类内使用成员变量{}, 类外使用属性@property***"的结论了. 且将成员变量_peopleName设为@public会很不安全.

    ## 自定义成员变量的get/set方法

    仍然将成员变量_peopleName默认为@protected, 从类内部的方法中对_peopleName进行读取或赋值, 然后间接传递至类外部, 是一个不错的选择.

    首先, 在.h中声明getName和setName方法:

    ```objective-c

    // People.h

    @interface People : NSObject

    {

    NSString *_peopleName;

    }

    -(NSString *)getName;

    -(void)setName:(NSString *)name;

    @end

    ```

    在.m中, get/set这两个方法是以***在类内部对成员变量_peopleName进行调用或赋值***的方式来实现的.

    ```objective-c

    // People.m

    -(NSString *)getName {

    return _peopleName;

    }

    -(void)setName:(NSString *)name {

    _peopleName = name;

    }

    ```

    那么, 调用的时候就非常方便了:

    ```objective-c

    // main.m

    People *p1 = [[People alloc] init];

    NSLog(@"p1.getName : %@", p1.getName);

    [p1 setName:@"people name 2"];

    NSLog(@"p1.getName : %@", p1.getName);

    ```

    结果如下:

    ```objective-c

    2015-05-06 16:25:36.019 memberAndProperty[3036:320317] p1.getName : people name 1

    2015-05-06 16:25:36.020 memberAndProperty[3036:320317] p1.getName : people name 2

    ```

    使用自定义的get/set, 从类内部调用成员变量是一种比较常见的方式. 但需手动添加这两个方法.

    ## 属性

    那么, 有没有更加简便的方法呢? 或者说, get/set这种非常常见的操作, 能不能默认提供给我们呢? 答案是肯定的!

    在新的iOS SDK中, 使用@property来定义类的属性, 是专用于从类外部对其进行调用或赋值的.

    在.h中先声明peopleName属性:

    ```objective-c

    // People.h

    @interface People : NSObject

    {

    NSString *_peopleName;

    }

    @property(nonatomic, strong) NSString *peopleName;

    // nonatomic 非原子性访问, 不加同步机制, 多线程并非访问时可提高性能

    // strong 相当于一个深拷贝的操作

    @end

    ```

    在.m中使用@synthesize指令将peopleName属性与_peopleName成员变量关联起来:

    ```objective-c

    // People.m

    @implementation People

    @synthesize peopleName = _peopleName;

    - (instancetype)init

    {

    self = [super init];

    if (self) {

    _peopleName = @"people name 1";

    }

    return self;

    }

    @end

    ```

    即, 编译器遇到@synthesize peopleName = _peopleName;时, 会自动生成对peopleName的get/set方法.

    且这里的下划线_是必不可少的, 否则就不能正确地将属性与成员变量关联起来.

    然后, 我们直接调用即可:

    ```objective-c

    // main.m

    People *p1 = [[People alloc] init];

    NSLog(@"p1.peopleName : %@", p1.peopleName);

    p1.peopleName = @"people name 2";

    NSLog(@"p1.peopleName : %@", p1.peopleName);

    ```

    结果如下:

    ```objective-c

    2015-05-06 16:32:29.142 memberAndProperty[3094:325295] p1.peopleName : people name 1

    2015-05-06 16:32:29.143 memberAndProperty[3094:325295] p1.peopleName : people name 2

    ```

    实际上, 编译器比我们想象中更聪明, 在.h文件中的{ NSString *_peopleName; }这个成员变量不需要声明也可以. 仅仅声明了@property(nonatomic, strong) NSString *peopleName;这个属性, xcode也会默认自动为我们声明一个该类的_peopleName成员变量, 及隐藏的get/set方法. 这里, 就体现出了下划线 _ 的作用了.

    ## 结论

    结论依然是:  ***类内使用成员变量{}, 类外使用属性@property***.

    因此在类外的话, 强烈推荐使用属性@property.

    而如果非要在类外使用成员变量{}, 则要么将该成员变量设为@public, 要么自定义其get/set方法, 利用这两个方法从类内部对成员变量进行调用或赋值. 这两种方法各自的弊端及使用请参考以上内容.

    相关文章

      网友评论

        本文标题:Objective-C中类的成员变量与属性

        本文链接:https://www.haomeiwen.com/subject/qdtuqttx.html