iOS 成员变量、实例变量、属性解析

1、成员变量、实例变量

@interface ViewController (){
    NSString *_type;
    NSString *_gender;
    NSInteger _age;
}

@property(nonatomic,copy) NSString *name;

@end

{ }中声明的变量是成员变量,@property申明的是属性,那么实例变量又是什么?变量类型为对象的成员变量就是实例变量,_type_gender就是实例变量,实例变量是成员变量的特殊情况

成员变量 = 基本数据类型变量 + 实例变量

成员变量 : 用于类内部,因为成员变量不会生成settergetter方法,所以外界无法访问成员变量。

成员变量访问方式如下:

 _type = @"ttt";
 NSLog(@"_type ==== %@",self->_type);

_type赋值,通过_typeself->_type两种方式都是OK的

2、属性

@property申明的是属性

2.1、Class中的property

编写如下代码:

- (void)viewDidLoad {
    [super viewDidLoad];
    self.name = @"123";
    _name = @"123";
}
- (void)setName:(NSString *)name{
    _name = name;
    NSLog(@"setName 被调用%s",__func__);
}

name赋值,可以通过self.name_name 两种方式进行访问
通过self.name访问属性时,setName会被调用,而通过_name访问属性,setName不会被调用

为什么通过self.name访问属性时,setName会被调用?

在oc中点表达式其实就是调用对象的settergetter方法的一种快捷方式

如果点表达式出现在等号左边,该属性名称的setter方法将被调用,如果点表达式出现在等号右边,该属性名称的getter方法将被调用。

为什么可以通过_name进行访问呢?

iOS5之前声明一个能被外面访问的属性,必须声明属性跟与之对应的成员变量,settergetter方法

@interface ViewController (){
    NSString *_name;
}
@property(nonatomic,copy) NSString *name;
@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
}

- (void)setName:(NSString *)name{
    _name = name;
    NSLog(@"setName 被调用%s",__func__);
}
- (NSString *)name{
    NSLog(@"getName 被调用%s",__func__);
    return _name;

}

但是iOS5之后,苹果是建议以下的方式来使用:

@interface ViewController ()
@property(nonatomic,copy) NSString *name;

@end

什么都不写,默认生成成员变量_namesettergetter方法

由此可见:property的本质 = ivar(成员变量) + getter + setter;

因为编译器会自动编写访问属性所需的方法,此过程叫做“自动合成”( auto synthesis)。需要强调的是,这个过程由编译器在编译期执行,所以编辑器里看不到这些“合成方法” (synthesized method)的源代码。除了生成方法代码之外,编译器还要自动向类中添加适当类型的成员变量,并且在属性名前面加下划线,以此作为成员变量的名字。

此外可以通过 @synthesize语法来指定成员变量的名字,比如你想给name属性的成员变量改一下名字,不再使用_name进行访问,那么可以用@synthesize name = _newName;之后使用_name进行访问就会报错,因为name属性的成员变量名称是_newName咯。

@synthesize name; 就是将name属性的成员变量命名为name

但是,增加一个属性_newName,此时就会出现警告,属性_newName不能自动合成,因为已经存在一个名字相同的成员变量咯

警告

此时通过self._newName = @"123"进行赋值,就会出现崩溃,[ViewController set_newName:]: unrecognized selector sent to instance 0x7faeb241b2e0因为属性_newName没有自动合成,点语法又是访问setter方法,setter方法根本不存在,

总结下 @synthesize 合成成员变量的规则,有以下3点:

  1. 如果指定了的名称,会生成一个指定名称的成员变量;
  2. 如果没有指定成员变量的名称,会自动生成一个属性同名的成员变量;
  3. 如果这个成员变量已经存在,就不会自动合成

2.2、Protocol、Category中的property

一般情况下,不能向存在的类添加属性,因为property的本质 = ivar(成员变量) + getter + setter;

runtime库中,class_addIvar函数用于给类添加成员变量,但是文档中特别说明:

 @note This function may only be called after objc_allocateClassPair and before objc_registerClassPair. 
 *       Adding an instance variable to an existing class is not supported.

意思是这个函数只能在类创建(objc_allocateClassPair)类注册(objc_registerClassPair)之间使用,往已经的类中添加实例变量是不支持的,经过编译的类在程序启动后就已经加载runtime,没有机会调用addIvar,所以没有机会再添加实例变量,也就是不能添加属性了。

protocolcategory 中如何使用 property?

protocol 中使用 property 只会生成settergetter 方法声明,我们使用属性的目的,是希望遵守我协议的对象能实现该属性

category 使用 property 也是只会生成 settergetter 方法的声明,如果我们真的需要给 category增加属性的实现,需要借助于runrime的两个函数:objc_setAssociatedObjectobjc_getAssociatedObject

如给Person类创建一个分类,增加gender属性

#import "Person.h"

NS_ASSUME_NONNULL_BEGIN

@interface Person (gender)
@property (nonatomic , copy) NSString *gender;
@end

NS_ASSUME_NONNULL_END

#import "Person+gender.h"
#import <objc/message.h>

@implementation Person (gender)


- (void)setGender:(NSString *)gender{
    objc_setAssociatedObject(self, @"gender", gender, OBJC_ASSOCIATION_COPY_NONATOMIC);
}

- (NSString *)gender{
   return objc_getAssociatedObject(self, @"gender");
}

@end

3、@synthesize和@dynamic分别有什么作用?

  1. @property有两个对应的词,一个是 @synthesize,一个是 @dynamic。如果 @synthesize和 @dynamic都没写,那么默认的就是@syntheszie var = _var;
  2. @synthesize : 如果你没有手动实现 setter 方法和 getter 方法,那么编译器会自动为你加上这两个方法。
  3. @dynamic : 告诉编译器属性的 settergetter 方法由用户自己实现,不自动生成。(当然对于 readonly 的属性只需提供 getter 即可)。假如一个属性被声明为 @dynamic var,然后你没有提供 @setter方法和 @getter 方法,编译的时候没问题,但是当程序运行到 instance.var = someVar,由于缺 setter 方法会导致程序崩溃;或者当运行到 someVar = var时,由于缺 getter 方法同样会导致崩溃。编译时没问题,运行时才执行相应的方法,这就是所谓的动态绑定。

参考地址:
iOS中属性与成员变量的区别
招聘一个靠谱的iOS

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

推荐阅读更多精彩内容