美文网首页
iOS-Objective-C各种基本属性修饰符

iOS-Objective-C各种基本属性修饰符

作者: leo_guo | 来源:发表于2017-06-18 19:54 被阅读311次

属性修饰符是每一个iOS程序员每天工作中都会用到的基础内容,也是初学iOS首先会接触到的内容。但在我面试过十多个已经有过一定工作经验iOS程序员时,发现他们居然还是对每个属性修饰符的原理和用法不甚明了,甚至有很多一直都在错用。我便想在此对其加以详细整理,如有问题请大家及时指出,多多沟通,共同进步。

1.@property是什么?

先来用@property定义一个基本的字符串属性

@property (nonatomic,copy,readwrite)NSString *string;

一个object的属性允许其他object监督和改变他的状态。但是在一个设计良好的面向对象程序中,直接访问一个object的内部状态是不可能的。相反,存取器(getter setter)方法是一个抽象相互作用object的底层数据。

@Property是声明属性的语法,它可以快速方便的为实例变量创建存取器,并允许我们通过点语法使用存取器。

存取器(accessor):指用于获取和设置实例变量的方法。用于获取实例变量值的存取器是getter,用于设置实例变量值的存取器是setter。

总之,@Property在定义属性时会自动生成get和set方法。可以使用self.Obj的get方法来调用属性,并且在set和get方法中对属性做了内存管理。而非@property定义的属性则不能使用Self.Obj来调用。

@synthesize关键字可以配合@Property来使用,用于在使用@property定义了属性后修改这个属性。例如

#import <Foundation/Foundation.h>  
#import "User.h"  
  
//有时候我们不想定义属性为_开头的  
//这时候我们就可以使用@synthesize,来修改我们想要的属性名  
  
//这时候属性_userName变成了$userName  
  
@implementation User  
@synthesize userName = $userName;  
  
@end  

2.@property中的关键字

原子属性(atomic)和非原子属性(nonatomic)

nonatomic
当一个变量声明为nonatomic时,意味着多个线程可以同时对其进行访问
当一个变量声明为nonatomic时,它是非线程安全型,访问速度快;
当一个变量声明为nonatomic时,当两个不同的线程对其访问时,容易失控。
atomic
当一个变量声明为atomic时,意味着在多线程中只能有一个线程能对它进行访问
当一个变量声明为atomic时,该变量为线程安全型,但是会影响访问速度,
当一个变量声明为atomic时,在非ARC编译环境下,需要设置访问锁来保证对该变量进行正确的get/set

nonatomic和atomic的对比

1.atomic:原子属性,为setter方法加锁(默认就是atomic);
nonatomic:非原子属性,不会为setter方法加锁。

2.atomic:线程安全,需要消耗大量的资源;
nonatomic:非线程安全,适合内存小的移动设备。

iOS开发的建议:所有属性都声明为nonatomic。
尽量避免多线程抢夺同一块资源。
尽量将加锁、资源抢夺的业务逻辑交给服务器端处理,减小移动客户端的压力。

目前最常用的assign、copy、strong、weak

assign

用于非指针变量。用于基础数据类型 (例如NSInteger)和C数据类型(int, float, double, char, 等),另外还有id,其setter方法直接赋值,不进行任何retain操作。例如

@property (nonatomic,assign)NSInteger number;

weak

weak 用于指针变量,比assign多了一个功能,当对象消失后自动把指针变成nil,由于消息发送给空对象表示无操作,这样有效的避免了崩溃(野指针),为了解决原类型与循环引用问题.例如:

@property (nonatomic, weak)id<CustomDelegate> delegate;

注意:assign看起来跟weak一样,其实不能混用的,assign的变量在释放后并不设置为nil(和weak不同),当你再去引用时候就会发生错误,崩溃,EXC_BAD_ACCESS.

weak和assign都是引用计算不变,两个的差别在于,weak用于object type,就是指针类型,而assign用于简单的数据类型,如int BOOL 等。

copy

copy 用于指针变量,setter方法进行copy操作,与retain处理流程一样,先旧值release,再copy出新的对象,retainCount为1。这是为了减少对上下文的依赖而引入的机制。copy是在你不希望a和b共享一块内存时会使用到。a和b各自有自己的内存。例如

@property (nonatomic,copy)NSArray *array;

strong

strong:strong和retain相似,只要有一个strong指针指向对象,该对象就不会被销毁。用于指针变量,setter方法对参数进行release旧值再retain新值。例如

@property (nonatomic,strong)NSMutableArray *dataArr;

注意:在实际运用中copy和strong的用法很多人在系统属性定义时会搞混,一般可变类型的属性用strong,不可变的用copy,如NSArray、NSString、NSDictionary用copy,NSMutableArray、NSMutableString用strong,不可变的属性用strong会导致在指向可变的内存地址后会变成可变属性。可变的属性用copy修饰后,指向不可变的内存地址会变成不可变的属性,容易导致出错。

其它不常用:

retain

retain 是在MRC中使用的强引用方式, 在 ARC 下基本等同于 strong。
_unsafeunretained,很少用到
unsafe_unretained: 其实质等同于assign。与weak的区别就是指向的对象如果被释放,其不会被置为nil,而导致悬空指针的出现。它是ARC模式下非对象属性的默认值。

readwrite | readonly

readwrite 可读可写,既有get方法,又有set方法。
readonly 只读,只有get方法,没有set方法。

3.其它常用到的修饰符

1.const变量修饰符。

只有只读权限,意思是这个参数只能读,不能修改内容,谁近修饰谁。

2.register

//register int b = 0;变量前面加register修饰,编译器会优先将此变量放在寄存器中,这样对这个变量进行的各种操作及运算,会很快,(适用于嵌入式编程)当然CPU周边的用户可用空闲寄存器是有限的,所以当定义多个register修饰的变量后,当可用寄存器已被占完,后面的变量即便用register修饰,也是不起作用的,依然是在普通内存中为变量开辟空间。

3.static 静态变量

有时候我们非常希望,用一个小变量记录某函数调用的次数,解决这个问题
方法1、可以使用全局变量;但是由于所有函数都可以修改它,对于较大程序出了问题不好调,所以使用全局变量并不好。
方法2、可以在目标函数中定义一个static变量(测试会发现这个变量的地址已经不再栈区,而是在数据区),每次进入函数让其++,static作用在局部变量前,函数结束此变量的值不清空,即改变了此变量的生命期,而且直到整个程序结束,并且此变量的值只有在定义它的函数中才可以被使用和重新赋值。

4.extern 扩展变量修饰符

extern int n;
extern可以扩展全局变量或函数的作用范围,只有全局变量或函数才可以用extern扩展
extern与register的区别

extern可以用来扩展函数的作用范围,可以跨文件扩展,前提是被扩展全局变量或者函数在定义时没有被static修饰!

5.MRC中

release 对象引用计数-1 如果为0释放内存
autorelease 对象引用计数-1 如果为0不马上释放,最近一个个pool时释放

6.其它

__block __weak__strong

__block

Blocks可以访问局部变量,但是不能修改
如果修改局部变量,需要加__block 例如

__block int i=0;
    [self setBlock:^{
       i=5;
    }];

__weak

若附有__weak 修饰符的变量所引用的对象被废弃,则将nil 赋值给该变量。
使用附有__weak 修饰符的变量,即是使用注册到autoreleasepool 中的对象。例如

__weak __typeof(&*self)weakSelf =self;

__strong

__strong 是缺省的关键词。用在block中方式属性被提前释放,例如

__strong typeof(weakSelf) self = weakSelf;

以上两种用法常搭配在防止block循环引用中,block循环引用的具体原理不在此做详细阐述,一般是在block中用self调用本类属性时会出现,一般用如下方法处理

__weak typeof(self) weakSelf = self;
    [self setBlock:^{
        __strong typeof(weakSelf) self = weakSelf;
        self.string = @"hello world";
    }];

常用的属性修饰符基本归纳整理完毕,关于其详细原理每个都可以写出大量篇幅,在此只整理出日常用法和基本原理,其它细节在后续内容中在做详细解释,文章中有引用到其它博客的部分语句,如有不足之处,还请大家多多指导,后续会逐渐补充。为更快提升自己,以后每周更新一篇,请大家监督😁。

相关文章

  • iOS-Objective-C各种基本属性修饰符

    属性修饰符是每一个iOS程序员每天工作中都会用到的基础内容,也是初学iOS首先会接触到的内容。但在我面试过十多个已...

  • iOS-Objective-C的属性修饰符(转)

    转自:http://blog.csdn.net/linyousong/article/details/507621...

  • [15]Effective Objective-C 2.0【6-

    第二章:对象、消息、运行期 第六条:理解“属性”这一概念 这一条讲的是属性的基本概念,以及属性的各种修饰符,这里强...

  • IOS各种属性修饰符

    nonatomic:访问速度快,但是线程间属性或者变量的调度是不安全的!比如:在一个线程里面调用了其get方法,另...

  • iOS-属性修饰符

    iOS开发中属性修饰符基本上每天都会打交道,网上总结也很多,本文按照实际开发的角度简单介绍一下属性修饰符,属性修饰...

  • Block

    Block基本语法 typedef声明,作Method参数使用 属性声明,使用copy修饰符 基本语法 声明Blo...

  • 2018-11-28

    1、CABasicAnimation基本动画 各种属性 CABasicAnimation基本动画 各种属性 - u...

  • 关于iOS基本属性修饰符的理解(weak篇)

    属性修饰符,顾名思义就是修饰属性的符号,针对不同的属性和使用场景有不同的属性修饰符作用:1、weak属性修饰符用来...

  • iOS属性修饰符的作用

    strong 修饰符(与retain的作用基本相同) 1.strong是一个属性的默认修饰符。2.strong修饰...

  • TS基础篇7:类基础

    第一:基本语法 第二:修饰符 第三:get , set 访问器(用public修饰符) 第四:静态属性 第五:类继承

网友评论

      本文标题:iOS-Objective-C各种基本属性修饰符

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