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

在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方法, 利用这两个方法从类内部对成员变量进行调用或赋值. 这两种方法各自的弊端及使用请参考以上内容.

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,222评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,455评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,720评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,568评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,696评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,879评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,028评论 3 409
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,773评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,220评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,550评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,697评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,360评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,002评论 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,782评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,010评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,433评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,587评论 2 350

推荐阅读更多精彩内容