美文网首页
iOS 属性关键字

iOS 属性关键字

作者: 萨缪 | 来源:发表于2020-04-27 22:32 被阅读0次
@property

功能:

给现有的成员变量生成一对setter、getter方法
如果没有声明成员变量时自动生成一个下划线开头的实例变量
在.m文件中,可以直接使用_myString访问实例变量,也可以通过self.myString访问属性的setter/getter方法

@property(strong, nonatomic)NSString *name; //直接自动生成成员变量_name和setter/getter方法

自定义getter/setter方法名

@property (getter = isHidden) BOOL hidden;

上述代码告诉编译器生成名为isHidden的getter方法,并生成名为默认setHidden:的setter方法。

setter和getter方法的命名
不影响成员变量的名称
setter = setAbc: 决定了setter方法的名称,一定要有个冒号
getter = abc 决定了getter方法的名称(一般用在BOOL类型)
例子:
@property(getter = abc, setter = setAbc)int weight;
一般在BOOL类型的属性声明时修改getter方法名为:is+描述

@property(getter = isRich)BOOL rich;

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

@property 有两个对应的词,一个是 @synthesize,一个是 @dynamic。如果 @synthesize 和 @dynamic 都没写,那么默认的就是 @syntheszie var = _var;

@synthesize 的语义是如果你没有手动实现 setter 方法和 getter 方法,那么编译器会自动为你加上这两个方法。

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

nonatomic和atomic

原子性
(联想事务原子性:一件事若由于客观原因没做完整,则回退到最初的状态)
nonatomic 为线程不安全的
atomic 为线程安全(默认)
atomic属性关键字修饰会产生什么效果:
会保证属性赋值和获取是线程安全的。比如修饰的是一个数组,那么我们对数组进行赋值和获取是线程安全的,但是如果给数组添加、移除对象,是无法保证线程安全的。
需要注意的是atomiac: 不受其他线程的影响,在 get 一个属性时,立马给这个属性在当前线程加一个锁,只有当 get 完成后,才会解锁,才会同步其他线程的 set 值。
而nonatomic: 受线程影响,在 get 一个属性时, 不管是否有其他线程执行 set 方法, 只返回 get 结束时的 set 值。
从这也可以看出,nonatomic 声明的属性,执行速率上是要更快一点的 ; 其实 atomiac 这个属性在上层代码中,其实非常不常用,因为很少会遇到存在同时,多个线程对一个属性 set 。

在iOS开发中为了性能都设置为nonatomic,线程安全问题通过其他方式解决
可写性,是否要生成set方法

readwrite与readonly
readwrite 可读可写(默认)
readonly 只读,编译器将只生成getter方法,不生成setter方法

词意上理解,readwrite 读写,readonly 只读。属性默认是 readwrite , 支持读写。

这对 CP,是对set 和 get 方法的一个总开关。
readwirte: 属性同时具有 set 和 get 方法。
readonly: 属性只具有 get 方法。
这俩关键字,就是和其词意一样 ,若只想类内部 set , 就声明 readonly。

retain 是说明该属性在赋值的时候,先release之前的值,然后再赋新值给属性,引用再加1。

retain源码解析

copy 对象的属性声明,操作的是复制的另一块内存
copy
复制的意思,意思非常明确,但用起来是最要注意的。
这个关键字类似 strong ,只能修饰 NSObject 对象,不能修饰基本数据类型。和 strong 不一样的地方是, copy 后的对象 ,指针地址是和之前不一样的,也就是说重新分配了一块内存,也就是所谓的深拷贝。这个关键字在用的时候,因为涉及到申请新的内存空间,所以要少用,能用 strong 的地方都用 strong ,只有必须用 copy 的地方才用 copy 。
另外要注意,copy 修饰可变类型的属性时要小心,如NSMutableArray、NSMutableDictionary、NSMutableString ,因为会容易造成 crash。

assign

这个关键字,是默认关键字,可以修饰基本数据类型和 NSObject 对象。
对这个关键字声明的属性操作时,retainCount 是一直不变的,一直为 1,只有主动调用 release 时 ,才会释放。
但是为什么我们不会用assign去声明对象呢?
这是因为 assign 修饰的对象(一般编译的时候会产生警告:Assigning retained object to unsafe property; object will be released after assignment)在释放之后,指针的地址还是存在的,也就是说指针并没有被置为nil,造成野指针。对象分配在堆上的某块内存,如果在后续的内存分配中,刚好分到了这块地址,程序就会 crash。
为什么可以用assign修饰基本数据类型?
因为基础数据类型是分配在栈上,栈的内存会由系统自己自动处理回收,不会造成野指针。

retain和copy还有assign的区别

假设你用malloc分配了一块内存,并且把它的地址赋值给了指针a,后来你希望指针b也共享这块内存,于是你又把a赋值给(assign)了b。此时a和b指向同一块内存,请问当a不再需要这块内存,能否直接释放它?答案是否定的,因为a并不知道b是否还在使用这块内存,如果a释放了,那么b在使用这块内存的时候会引起程序crash掉。

了解到1中assign的问题,那么如何解决?最简单的一个方法就是使用引用计数(reference counting),还是上面的那个例子,我们给那块内存设一个引用计数,当内存被分配并且赋值给a时,引用计数是1。当把a赋值给b时引用计数增加到2。这时如果a不再使用这块内存,它只需要把引用计数减1,表明自己不再拥有这块内存。b不再使用这块内存时也把引用计数减1。当引用计数变为0的时候,代表该内存不再被任何指针所引用,系统可以把它直接释放掉。

上面两点其实就是assign和retain的区别,assign就是直接赋值,从而可能引起1中的问题,当数据为int, float等原生类型时,可以使用assign。retain就如2中所述,使用了引用计数,retain引起引用计数加1, release引起引用计数减1,当引用计数为0时,dealloc函数被调用,内存被回收。

copy是在你不希望a和b共享一块内存时会使用到。a和b各自有自己的内存。

strong 强指针 增加一个对象的引用权限(引用计数+1)
在ARC环境下,__strong修饰符是默认的修饰符,也就是说我们写的代码虽没有明确写明所有权修饰符,但其实默认为__strong。
id obj = [[NSObject alloc] init];

// 其实默认为__strong修饰符
id __strong obj = [[NSObject alloc] init];

那__strong修饰符有什么用呢?** __strong修饰符表示对对象的“强引用”。持有强引用的指针在超出其作用域时被废弃,随着强引用的消失,引用的对象也随之被释放。**
// ARC下
id __strong obj = [[NSObject alloc] init];

上面代码等同于下面代码:
{ // 非ARC下
id obj = [[NSObject alloc] init];

// ....作用域内

[obj release];

}

weak 不会增加一个对象的引用权限,只能指向对象,不持有指向对象的所有权
weak修饰符的存在是为解决“循环引用”问题而引入的,它是弱引用,弱引用不持有对象。

id __weak obj1 = nil;
{
    id __strong obj0 = [[NSObject alloc] init];
    obj1 = obj0;
    NSLog(@"作用域内:obj0:%@----obj1:%@",obj0,obj1);
}
NSLog(@"作用域外:obj1:%@",obj1);

// 超出了作用域obj0释放,对象被废弃,则obj1这个弱引用自动失效并被赋值为nil

作用域内:obj0:<NSObject: 0x7fdcc1446f10>----obj1:<NSObject: 0x7fdcc1446f10>
作用域外:obj1:(null)

另外:__weak修饰的对象,都会被注册到自动释放池autorelease中。
所以,我们应该避免大量使用__weak,只有在需要避免循环引用等问题时使用它。

上面说的避免大量使用有不要随便定义__weak修饰的对象的意思,也有避免:一个__weak修饰的对象若被使用多次,则就注册到自动释放池中多次;所以我们有时为内存着想,可以将该对象赋值给一个__strong修饰的对象,以供后续使用,这样只会被注册到自动释放池中一次。

strong和weak的区别:

strong 是每对这个属性引用一次,retainCount 就会+1,只能修饰 NSObject 对象,不能修饰基本数据类型。是 id 和 对象 的默认修饰符。
weak 对属性引用时,retainCount 不变,只能修饰 NSObject 对象,不能修饰基本数据类型。主要用于避免循环引用。

assign和weak关键字区别:

assign关键字可以修饰int等基本数据类型
assign关键字修饰的时候不改变引用计数
assign关键字修饰的对象会产生悬垂指针。对象在被释放后,assign指针仍会指向原内存地址,此时通过assign指针继续访问原对象的话,会导致内存泄露和程序异常。
weak关键字不改变修饰对象的引用计数
weak修饰的对象在被释放后指针会被自动置为nil

非对象类型用 assign 可省略
对象类型用 retain/strong
NSString用 copy/strong

在实际项目中:

NSString属性,一般用strong修饰;但如果要防止在其他地方被修改,则用copy修饰。
block类型的属性一定要用copy修饰
1,NSGlobalBlock 全局类型 不访问外部变量,相当于一个普通函数
2,NSMallocBlock ARC下访问了外部变量, 存储在堆区 (自动进行了复制)
3,MSStackBlock MRC下访问了外部变量, 存储在栈区

默认情况下,block是存在栈中,可能被随时回收,通过copy操作,可以使其在堆中保留一份,相当于一直强引用着,因此如果block中用到self时,需要将其弱化,通过__weak或者__unsafe_unretained。

那么上文经常提到的引用计数又是什么呢?

看这个引用计数总结

alloc:
alloc方法里面调用的allocWithZone:方法,传入内存区域生成内存空间,但现在几乎不在乎内存NSZone的问题了,基本采用默认分配方式分给对象内存空间,随即将其置0。
alloc创建对象后是自动持有的,即引用计数为1。

在GNUstep框架中在对象内存头部有一块空间(整数)来记录该对象当前引用计数,读取引用计数的方法retainCount实现机理即是访问该小空间的整数retained。而retain就使其递增retained++,release则递减retained--。当retained == 0时,调用dealloc废弃该对象。
苹果生成对象的原理和GNUstep差不多,但是引用计数的管理却有不同,苹果采用哈希表来管理对象的引用计数,该表的key为哈希化的内存块地址,value为其引用计数。

iOS9的几个新关键字(nonnull、nullable、null_resettable、__null_unspecified 、__kindof)

nonnull
字面意思就能知道:不能为空(用来修饰属性,或者方法的参数,方法的返回值)

nullable
表示可以为空

null_resettable
get 不能返回空, set 可以为空(注意:如果使用null_resettable,必须重写 get 方法或者 set 方法,处理传递的值为空的情况))

__null_unspecified
不确定是否为空 (很操蛋。。。)

__kindof
放在类型前面,表示修饰这个类型(__kindof MyCustomClass *)
表示当前类,也可以表示当前类的子类

相关文章

  • iOS属性关键字

    iOS属性关键字 引言 学习 iOS 开发的人,大多都绕不开属性关键字—— assign,weak,unsafe_...

  • iOS开发---属性关键字详解

    iOS开发—属性关键字详解 @Property 什么是属性? 属性(property)是Objective-C的一...

  • iOS objective-c 属性关键字

    首先iOS objective - C有以下属性关键字strongweakassignatomicnonatomi...

  • iOS - 基础

    iOS 属性修饰关键字都有哪些? atomic 原子性访问,对属性赋值的时候加锁 noatomic 非原子...

  • ios9新特性(关键字)

    嗯嗯,马上就要 发布iOS新的版本了。嗯,码农又该忙碌了 ios9新特性(关键字) 新出的关键字:修饰属性,方法的...

  • iOS 中weak的实现

    只要学过 iOS 的人,都会对 strong、weak、copy等关键字应该都会很熟悉。weak 属性关键字就是弱...

  • IOS 常用关键字基础大全

    ios声明属性时,在ARC环境下常用到的关键字,readonly、readwrite、nonatomic、...

  • iOS中的修饰关键字

    1. iOS中定义属性、变量的修饰关键字 在声明@property 属性、变量时,总是要在括号中写上assign、...

  • iOS-归纳

    iOS内存分区,堆区 栈区等 内存管理 属性关键字、内存分区总结 iOS- 数据存储iOS开发数据库-FMDBiO...

  • iOS9新特性之关键字

    iOS9新特性之关键字 iOS9新出的关键字:用来修饰属性,或者方法的参数,方法的返回值 好处:1.迎合swift...

网友评论

      本文标题:iOS 属性关键字

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