前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >property属性相关小记

property属性相关小记

作者头像
我只不过是出来写写代码
发布2019-04-02 15:00:13
1.1K0
发布2019-04-02 15:00:13
举报
文章被收录于专栏:我只不过是出来写写iOS

针对目前开发中已大多使用ARC自动引用计数技术,因此常用关键字有strong、weak、assign、copy、retain、nonatomic、atomic

strong:释放旧对象将旧对象的值赋予输入对象,再将输入对象的索引值计数增加1

weak:不增加引用计数,不持有对象,所以不能决定对象的释放,对比assign好处是,当对象消失时指针自动归为nil

assign:适用于基础数据类型,不增加引用计数,如(NSInteger、CGFloat、int等)

copy:建立一个索引计数为1的对象,然后释放旧对象,对实行了NSCopying协议的对象类型有效(NSString、NSDictionary、NSArray、block)

nonnull与nullable:是iOS9之后的新特性,用于声明属性是否可以为nil,若对nonnull属性赋值nil时,则会报警告。用于调用属性时可以知道该属性是否可能为nil,并针对处理。默认情况下为nullable状态,可以赋值为nil

atomic:与nonatomic相对应,用于决定编译器生成的getter和setter是否为原子操作,atomic设置成员变量@property属性时,默认为atomic提供线程安全

nonatomic:非原子性访问对于属性赋值时不加锁,多线程并发访问会提高性能,若不加此属性则默认setter和getter方法都为原子性访问

readonly:此属性为只读

readwrite:可读写,默认属性

何为原子性访问?

当多线程环境下同时调用一个setter时,可能会出现无法获取完整的数据。使用atomic属性时,则会一个线程在执行完setter全部语句前,不会让另一个线程开始执行setter,以此保证数据完整性。因此,在多线程环境下执行原子性访问是很有必要的,但同时原子性操作会耗费系统资源。

其它扩展问题:

  1. 为何delegate的声明都设置weak属性

主要是为了防止循环引用问题。

弱引用

在VC中,VC的view就是tableview,相当于VC强引用着tableview。当设置delegate时,是为了让tableview成为代理,若此时代理设置为强引用,则tableview的delegate强引用VC,导致了循环引用。

  1. 为何block声明都设置为copy属性

在声明为copy后,block才会在堆中,栈中的block生命周期是和栈绑定的。也可以用retain,block的retain行为默认为copy行为实现的,block变量默认是声明为栈变量的,为了能在block的声明域外使用,所以要把block copy到堆中,为了属性声明和实际操作一致,最好声明为copy。

线程安全问题,声明block属性时,需要确认是否有多个线程同时访问修改block。若没有,则声明为nonatomic,若不确定时,使用atomic。为了安全起见,在调用时需要把block先赋值给本地变量,以防止block改变。若不这么操作,即使先判断了block不为空,调用前,一旦另一个线程把block置为空,程序会crash。

代码示例:

代码语言:javascript
复制
if (self.myBlock)
{

    //此时,走到这里,self.myBlock可能被另一个线程改为空,造成crash

    //注意:atomic只会确保myBlock的原子性,这种操作本身还是非线程安全的

    self.myBlock(123);

}

所以正确的代码是(ARC):

代码语言:javascript
复制
MyBlockType block = self.myBlock;

//block现在是本地不可变的

if (block)

{

    block(123);

}

在MRC环境下,需要手动retain一下,以防变量变为野指针。

  1. 何为堆和栈?

Objective-C对象所占内存总是分配在“堆空间”,且堆内存由开发者释放,即release;

由编译器管理自动释放的,在方法中定义的变量通常在栈内。

栈区(stack):由编译器自动分配释放,存放函数的参数值,局部变量等值。其操作方式类似于数据结构中的栈。

栈对象: 优点: 1.高速,在栈上分配内存是非常快的。 2.简单,栈对象有自己的生命周期,你永远不可能发生内存泄露。因为他总是在超出他的作用域时被自动销毁了 在objective-c中只支持一个类型对象:block 堆区(heap):一般由程序员分配释放,若程序员不释放,则可能会引起内存泄漏。注 堆和数据结构中的堆栈不一样,其类似于链表。 缺点: 栈对象严格的定义了生命周期也是其主要的缺点,栈对象的生命周期不适于Objective-C的引用计数内存管理方法。

堆对象: 优点:可以自己控制对象的生命周期。 缺点:需要程序员手动释放,容易造成内存泄漏。

  1. 声明NSString、NSArray、NSDictionary时,通常使用copy而不是strong属性?

一般情况下,不希望字符串的值跟着变化时,使用copy;希望属性变量跟着变化,就使用strong。

以上情况是针对NSMutableString赋值为NSString时,才会有所不同。若都为NSString,则使用copy和strong都一样,NSString本身不能改变自身的值,是不可变的。

因此,对于源头是可变变量时,不可变变量仅仅是指针引用,当源头改变时,若使用strong声明,不可变变量会跟随变化;而copy声明,是深拷贝,不会跟随改变。

  1. weak属性需要在dealloc中置nil么?(runtime如何实现weak变量自动置nil)

不需要。在释放时,调用clearDeallocating函数。该函数首先根据对象地址获取所有weak指针地址的数据,然后遍历数据把其中的数据置为nil,最后把记录从weak表中删除,清理对象的记录。

原理:weak对象会放入一个hash表中,用weak指向的对象内存地址作为key,因此该对象引用计数为0时就回dealloc,在hash表中找到所有以该对象内存地址为key的weak对象,从而置为nil。

  1. 当weak引用指向的对象释放时,如何去处理weak指针的呢?

(1)、调⽤用objc_release

(2)、因为对象的引⽤用计数为0,所以执行dealloc

(3)、在dealloc中,调⽤用了了_objc_rootDealloc函数

(4)、在_objc_rootDealloc中,调⽤了object_dispose函数

(5)、调用objc_destructInstance

(6)、最后调用objc_clear_deallocating,详细过程如下:

a. 从weak表中获取废弃对象的地址为键值的记录

b. 将包含在记录中的所有附有 weak修饰符变量量的地址,赋值为 nil

c. 将weak表中该记录删除

d. 从引⽤用计数表中删除废弃对象的地址为键值的记录

  1. ARC下,不显式指定任何属性关键字时,默认关键字有哪些?

基本数据类型: atomic、assign、readwrite

基本OC对象: atomic、strong、readwrite

  1. @synthesize和@dynamic作用

@property有两个对应词,一个是@synthesize,一个是@dynamic。若都没声明,则默认是@synthesize var = _var;

@synthesize若无手动实现setter方法和getter方法,编译器会自动加上两个方法

@dynamic告诉编译器,setter和getter方法由用户实现,不自动生成。对于只读属性的只需提供getter即可。当一个属性被声明为@dynamic var并没有提供getter和setter方法,当执行到需要setter和getter方法时,导致崩溃。编译通过,执行时才执行相应方法,即所谓的动态绑定。

  1. @synthesize合成实例变量规则

a. 若指定了成员变量的名称,则会生成一个指定名称的成员变量 b. 若成员已经存在,则不再生成

  1. 在protocol和category中如何使用@property

在两者中,都会生成setter和getter方法的声明。protocol中是希望遵守协议中的对象实现该属性;category需要增加属性的实现时,需要分别使用两个函数:objc_setAssociatedObject和objc_getAssociatedObject

  1. 什么情况下@property不会autosynthesize(自动合成)?

重写只读属性的getter时;

重写setter和getter时

使用了@dynamic时

@protocol中定义了所有属性时

在category定义了所有属性时

重载了属性时

  1. 能否向编译后的类中添加实例变量,能否向运行时创建的类添加实例变量?为什么?

不能向编译后得到的类增加实例变量

可以向运行时创建的类添加实例变量

原因:

编译后的类已经注册在runtime中,类结构体中objc_ivar_list实例变量的链表和instance_size实例变量的内存大小已确定,runtime会调用class_setvarlayout或class_setWeaklvarLayout来处理strong、weak引用。所以不能向存在的类中增加实例变量。

运行时创建的类可以添加实例变量,是调用class_addIvar函数,但是在调用objc_allocateClassPair之后,objc_registerClassPair之前

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2018.05.21 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档