iOS成员变量、实例变量、成员属性、@property、@synthesize和 @dynamic 说明

一、iOS成员变量、实例变量、成员属性说明:

1、成员变量、实例变量:

1)、成员变量是在{}中声明的变量,如下代码所示:
2)、如果成员变量的类型是一个类则称这个变量为实例变量
3)、成员变量包括实例变量,所以可以通称为成员变量(这里只是便于概念理解分开解释)

实例变量 = 成员变量 = ivar
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@interface Persion : NSObject{
    NSString *name; //实例变量
    int age;        //成员变量
}
@end
NS_ASSUME_NONNULL_END

2、成员属性(也可称属性变量):

通常我们使用@property声明的变量都叫做成员属性,也可称属性变量。

3、成员变量和成员属性的关系:

1、属性对成员变量扩充了存取方法 (例如在get和set方法中做其他逻辑);
2、属性默认会生成带下划线的成员变量 ;
3、但只声明了变量,是不会有属性的,可以通过以下代码证明:
在Person.h 头文件中

@interface Person : NSObject {
    @private
    //name为私有成员变量
    NSString *name;
}
 // age 为成员属性
@property (nonatomic ,copy) NSString *age;

在viewController.m 中,通过RunTime机制获得对象的所有成员变量和成员属性。

    Person *p = [Person new];
    unsigned int count = 0; //count记录变量的数量
    
    // 获取类的所有成员变量
    Ivar *members = class_copyIvarList([Person class], &count);
    for (int i = 0; i < count; i++) {
        Ivar ivar = members[i];
        // 取得变量名并转成字符串类型
        const char *memberName = ivar_getName(ivar);
        NSLog(@"变量名 = %s",memberName);
    }
    // 获取类的所有成员属性
    objc_property_t *properties =class_copyPropertyList([Person class], &count);
    for (int i = 0; i<count; i++)
    {
        objc_property_t property = properties[i];
        const char* char_f =property_getName(property);
        NSString *propertyName = [NSString stringWithUTF8String:char_f];
        NSLog(@"属性名 = %@",propertyName);
    }

打印结果为

变量名 = name
变量名 = _age
属性名 = age

二、@property、@synthesize、@dynamic说明:

1、@property

@property是用来定义成员属性的,通常情况会自动合成成员变量和set/get方法。

简单来说:我们写@property声明属性,其实是做了三件事(@property = _ivar + getter + setter):
.h: 声明了getter和setter方法;
.m: 声明了成员变量(默认:下划线+属性名);
.m: 实现了getter和setter方法。

以上三件事是由编译器自动加上了@synthesize关键字的功能,只是常规情况下默认省略了。

  1. 如果这个成员变量(同名_ivar)已经存在,@property就不再生成新成员变量;
  2. 默认合成的成员变量创建后默认是@private类型,只能在本类中访问,子类也无法访问父类默认生成的成员变量_ivar;
  3. 在.h声明的成员变量会被子类访问,是@protected类型。(补充:.h中声明的成员变量都是protected,想要被非子类访问需要用@public修饰)

接下来先看看以下问题:
1、那@synthesize,@dynamic到底是干什么的?
2、什么情况下不会自动合成成员变量和set/get方法呢?

2、@synthesize

@synthesize 是配合@property使用的。字面意思是合成,这个关键字在默认情况下可以省略,编译器自动会实现这个关键字的功能,也可以手动加上实现。

  1. 如果属性没有手动实现setter和getter方法,编译器为你自动生成setter与getter方法;
  2. 可以指定与属性对应的实例变量(例如:@syntheszie ivar = _ivar123,就会为成员属性ivar生成一个_ivar123的成员变量);
  3. 如果子类中有和父类重名的属性,就会报错:
    Auto property synthesis will not synthesize property 'name';
    it will be implemented by its superclass, use @dynamic to acknowledge intention
    这是因为当编译器检测到父类相同属性的时候子类不会自动生成@sythesize ivar = _ivar,此时子类只有属性没有生成对应成员变量_ivar,也不会有对应的set和get方法。
    在子类调用self.ivar时实际上是调用父类的属性。一旦这个子类的属性是开发者自定义的,开发者用这个属性调用方法时用了自定义的方法,这个方法父类属性没有的时候,就会造成崩溃;
    这个时候可以在子类添加@syntheszie ivar = _ivar ,子类会生成自己私有的_ivar成员变量,这个时候子类的self.ivar也就会访问自己的属性。

另外,以下这些场景定义的属性不会合成成员变量:

1)同时重写了 setter 和 getter 时
2)重写了只读属性的 getter 时,如下第三部分readonly 和 writeonly情况下重写
3)使用了 @dynamic 时
4)在 @protocol 中定义的所有属性
5)在 category 中定义的所有属性
6)重载的属性(如果子类中有和父类重名的属性,就会警告,需要用@synthesize)

如果条件满足且需要成员变量可以使用@synthesize关键字来合成

3、@dynamic

@dynamic告诉编译器:属性的 setter 与 getter 方法由用户自己实现,不自动生成。

假如一个属性被声明为 @dynamic var,而且你没有提供 @setter方法和 @getter 方法,编译的时候没问题,但是当程序运行到 instance.var = someVar,由于缺 setter 方法会导致程序崩溃;或者当运行到 someVar = var 时,由于缺 getter 方法同样会导致崩溃。编译时没问题,运行时才执行相应的方法,这就是所谓的动态绑定。

三、重写getter和setter方法注意事项

只重写getter(懒加载):默认会自动生成下划线开头的变量,在getter中要使用下划线(return _ivar)来返回值,不能使用self.否则造成死循环

只重写setter:默认会自动生成下划线开头的变量,在setter中要使用下划线( _ivar= ivar)来接收值,不能使用self.否则造成死循环

两个都重写:同时手动重写了一个属性的get和set方法的话,Xcode不会再自动生成带有下划线的私有成员变量了这时如果不加,@synthesize就会报错,解决方法就是添加@syntheszie ivar = _ivar

readonly 和 writeonly情况下重写:这时属性只会生成getter或者setter方法,如果我们重写了该方法,就需要我们重新添加@synthesize

四、Objective-C 中的点语法

  • 点表达式(.)看起来与C语言中的结构体访问以及java语言汇总的对象访问有点类似,如果点表达式出现在等号 左边,调用该属性名称的setter方法。如果点表达式出现在右边,调用该属性名称的getter方法。
  • OC中点表达式(.)其实就是调用对象的settergetter方法的一种快捷方式,self.myString = @"张三";实际就是[self setmyString:@"张三"];

属性访问方式 :
这是我们最容易掌握的一种使用方式,所以甚至有的开发者在开发中只会定义属性
person .name = @"xiaoming";

指针访问方式 :
作为一个有洁癖的程序员,更多时候还是定义成员变量而不是属性,因为至少减少了一次方法调用,减少了内存占用
person->_name = @"xiaowang";

KVC访问方式 :
如果一个类的成员变量是私有的,然后我想访问它,可以使用KVC的方式
[person setValue:@"xiaohua" forKey:@"name"];

五、self.ivar和_ivar的区别

其中self.ivar是调用的xx属性的get/set方法,而_ivar则只是使用成员变量_ivar,并不会调用get/set方法。两者的更深层次的区别在于,通过存取方法访问比直接访问多做了一些其他的事情(例如内存管理,复制值等),例如如果属性在@property中属性的修饰符有retain,那么当使用self.xx的时候相应的属性的引用计数器由于生成了setter方法而进行加1操作,此时的retaincount为2

六、属性、成员变量、self.ivar、_ivar使用经验总结

  • 需要与外部类交互的都写成属性

  • 所有属性在使用时最好使用self.来调用,其他内部使用的对象尽量用成员变量定义(减少内存占用,调用更快)

  • 需要懒加载的对象定义为属性(或私有属性)

  • 重写getter(懒加载)和setter方法时在内部使用_ivar来操作,避免造成死锁。

七、其他

1、经常看到block里面有报警:

Block implicitly retains 'self'; explicitly mention 'self' to indicate this is intended behavior

block中使用了self的成员变量_ivar,因此block会隐式的retain住self。Xcode认为这可能会给开发者造成困惑,或者因此而因袭循环引用,所以警告我们要显示的在block中使用self,以达到block显示retain住self的目的。

参考:
iOS彻底搞清属性与成员变量
objective-c指针解引用

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

推荐阅读更多精彩内容