运行时runtime深度解析(五) —— 属性和成员变量(一)

版本记录

版本号 时间
V1.0 2019.05.02 星期四

前言

OC是运行时的语言,底层就是运行时,可以说runtime是OC的底层,很多事情也都可以用运行时解决,下面就讲述一下运行时runtime的知识以及它的妙用。感兴趣的可以看上面几篇。
1. 运行时runtime深度解析(一)—— API
2. 运行时runtime深度解析(二)—— Method Swizzling在页面统计上的应用
3. 运行时runtime深度解析(三)—— Method Swizzling在数组越界上的应用
4. 运行时runtime深度解析(四)—— 获取类的属性和方法列表

获取属性和成员变量列表

下面我们直接看示例代码,获取属性和成员变量列表:

#import "ViewController.h"
#import <objc/runtime.h>

@interface ViewController ()
{
    NSString *name;
}

@property (nonatomic, copy) NSString *age;

@end

@implementation ViewController

#pragma mark - Override Base Function

- (void)viewDidLoad
{
    [super viewDidLoad];
    
    self.view.backgroundColor = [UIColor greenColor];
    
    [self setupUI];
    
    //获取属性列表
    NSArray *propertyArr = [[self class] loadAllProperties];
    NSLog(@"属性列表 = %@", propertyArr);
    
    //获取成员列表
    NSArray *ivarsArr = [[self class] loadAllIvars];
    NSLog(@"成员列表 = %@", ivarsArr);
}

#pragma mark - Object Private Function

- (void)setupUI
{
    
}

#pragma mark - Class Public Function

//获取对象的所有属性
+ (NSArray *)loadAllProperties
{
    u_int count;
    
    //将count的地址传递过去
    objc_property_t *properties = class_copyPropertyList([self class], &count);
    
    NSMutableArray *propertyListArrM = [NSMutableArray arrayWithCapacity:count];
    
    for (int i = 0; i < count; i++) {
        //得到propertyName为c语言的字符串
        const char *propertyName = property_getName(properties[i]);
        //c字符串转化为oc字符串
        [propertyListArrM addObject:[NSString stringWithCString:propertyName encoding:NSUTF8StringEncoding]];
    }
    
    //class_copyPropertyList为底层c语言,我们使用完一定要记得释放properties
    free(properties);
    
    return [propertyListArrM copy];
}

//获取对象的所有方法
+ (NSArray *)loadAllIvars
{
    u_int count;
    
    //将count的地址传递过去
    Ivar *ivars = class_copyIvarList([self class], &count);
    
    NSMutableArray *ivarListArrM = [NSMutableArray arrayWithCapacity:count];
    
    for (int i = 0; i < count; i++) {
        //得到propertyName为c语言的字符串
        const char *ivarName = ivar_getName(ivars[i]);
        //c字符串转化为oc字符串
        [ivarListArrM addObject:[NSString stringWithCString:ivarName encoding:NSUTF8StringEncoding]];
    }
    
    //class_copyPropertyList为底层c语言,我们使用完一定要记得释放properties
    free(ivars);
    
    return [ivarListArrM copy];
}

@end

下面看一下输出结果

2019-05-02 14:10:47.324313+0800 JJRuntime[1452:55332] 属性列表 = (
    age
)
2019-05-02 14:10:47.324602+0800 JJRuntime[1452:55332] 成员列表 = (
    name,
    "_age"
)

大家可以看出来,属性列表可以看出来是age,但是成员列表相对就不一样了。

原因是苹果将默认编译器从GCC转换为LLVM(low level virtual machine)之后,直接使用@property时,编译器会自动为你生成以下划线开头的实例变量,所以成员变量列表里面有_age这一项。


区别和联系

1. 成员变量

作用范围

  • @public:在任何地方都能直接访问对象的成员变量。
  • @private:只能在当前类的对象方法中直接访问,如果子类要访问需要调用父类的getter/setter方法。
  • @protected:可以在当前类及其子类对象方法中直接访问(系统默认下是用它来修饰的)。
  • @package:在同一个包下就可以直接访问,比如说在同一个框架。

无论父类是在@interface还是@implementation声明的成员变量子类都能拥有;但是子类能不能直接通过变量名来访问父类中定义的成员变量是需要看父类中定义的成员变量是由什么修饰符来修饰的。

一种老的写法

下面是关于成员变量的一种比较老的写法,现在不用了。

@interface ViewController ()
{    
    NSString *_name;
}

@property (nonatomic, copy) NSString *name;

@end

@implementation ViewController

@synthesize name = _name;

@end

但是很多新的项目不会这么写了,一般都是写成下面这个样子了。

@interface ViewController ()

@property (nonatomic, copy) NSString *name;

@end

@implementation ViewController

@end

其实,发生这种状况的根本原因是苹果将默认编译器从GCC转换为了LLVM(low level virtual machine),才不再需要为属性声明实例变量了,在没有更改之前,属性的正常写法需要三个步骤:

成员变量 + @property + @synthesize 成员变量

如果只写成下面这个样子

// 成员变量 + @property 

@interface ViewController ()
{
    NSString *myString;    
}
@property (nonatomic, copy) NSString * myString;

@end

编译器会警告

Autosynthesized property '�myString' will use synthesized instance variable '_myString', not existing instance variable 'myString'

1) 但更换为LLVM之后,编译器会在编译过程中检查有没有相应的实例变量,发现没有相应的实例变量就会自动生成一个带下划线开头的实例变量。因此,现在我们不必再声明一个实例变量。(注意:是不必要,不是不可以)
2) @synthesize语句只能被用在implementation代码段中,@synthesize的作用就是让编译器为你自动生成settergetter方法,@synthesize 还有一个作用,可以指定与属性对应的实例变量,例如@synthesize myButton = xxx;那么self.myButton其实是操作的实例变量xxx,而不是_myButton了。
3) 如果.m文件中写了@synthesize myButton;那么生成的实例变量就是myButton;如果没写@synthesize myButton,那么生成的实例变量就是_myButton。所以跟以前的用法还是有点细微的区别。

上面部分是别人总结的,这里用了下,文章后面已经给出出处和链接。

下面还要多说下:

  • @property的作用是定义属性,声明getter、setter方法。(注意:属性不是变量)
  • @synthesize的作用是实现属性的,如getter,setter方法
  • @synthesize 声明的属性 = 变量。意思是:将属性的getter、setter方法,作用于这个变量。
  • Xocde4.5以后,编译器会为你自动实现setter及getter方法,如果他找不到_name,会为你自动创建一个_name的变量。

默认

  • 在.m中成员变量的修饰符为@private
  • 在.h中成员变量的修饰符@protected

2. 属性

  • 关于属性可以参考文档Objective-C 编程语言官网文档(五)-属性的声明
  • 对于属性重点看那几个属性修饰符的使用,这个就不赘述了,早就已经分篇进行了说明。
  • 属性声明以关键词@property开头。@property 可以出现在类的 @interface 块中方法声明的任何地方。
  • @property 还可以出现在protocol 或者 category声明中。
  • @property声明的属性不仅仅默认给我们生成一个_类型的成员变量,同时也会生成setter/getter方法。

3. 区别联系

成员变量用于类内部,无需与外界接触的变量。因为成员变量不会生成set、get方法,所以外界无法与成员变量接触。根据成员变量的私有性,为了方便访问,所以就有了属性变量。属性变量的好处就是允许让其他对象访问到该变量(因为属性创建过程中自动产生了set 和get方法)。当然,你可以设置只读或者可写等,设置方法也可自定义。所以,属性变量是用于与其他对象交互的变量。

综上所述可知:成员变量是定义在{}号中的变量,如果变量的数据类型是一个类则称这个变量为实例变量。因为实例变量是成员变量的一种特殊情况,所以实例变量也是类内部使用的,无需与外部接触的变量,这个也就是所谓的类私有变量。而属性变量是用于与其他对象交互的变量。可以这么说:实例变量 + 基本数据类型变量 = 成员变量。

参考文章

1. 黄增松的技术博客
2. iOS 成员变量和属性的区别
3. 成员变量和属性
4. 类的成员变量和属性

后记

本篇讲述了属性和成员变量区别,暂时先写这么多,感兴趣的给个赞或者关注~~~

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

推荐阅读更多精彩内容