速查备忘
OC基础之类别(Category)和扩展(Extension): https://www.jianshu.com/p/dc3196030a03
分类(category)和类扩展(extension)_西瓜的博客-CSDN博客
property关键字详解 :https://www.jianshu.com/p/d8f2d170f809
键值编程:https://www.jianshu.com/p/38fdad9689d2
Property
strong 强引用,引用计数+1,相当于MRC里的retain
weak 弱引用,不持有对象,不增加引用计数,在对象销毁后会自动置nil。(必须用于oc对象)
assign 弱引用 (赋值特性) ; setter方法将传入参数赋值给实例变量;仅设置变量时,assign用于基本数据类型(这个是关键)。
copy 拷贝特性。setter方法将传入对象复制一份,需要完全一份新的变量时。
copy
- block 使用 copy 是从 MRC 遗留下来的“传统”;
在 MRC 中,方法内部的 block 是在栈区的,使用 copy 可以把它放到堆区;
对于 block 使用 copy 还是 strong 效果是一样的。
- 使用copy的目的是,防止把可变类型的对象赋值给不可变类型的对象时,可变类型对象的值发送变化会无意间篡改不可变类型对象原来的值。
copy & strong
首先明确:NSString一旦创建后,其长度和内容都不可修改。
如果源字符串是NSMutableString的时候,使用strong只会增加引用计数。
但是copy会执行一次深拷贝,会造成不必要的内存浪费。而如果原字符串是NSString时,strong和copy效果一样,就不会有这个问题。
但是,我们一般声明NSString时,也不希望它改变,所以一般情况下,建议使用copy,这样可以避免NSMutableString带来的错误。
assign & weak(解释了为何assign允许不置空)
我们都知道,assign用来修饰基本数据类型,weak用来修饰OC对象。
其实照理,assign也能修饰OC对象,但是assign修饰的对象在该对象释放后,其指针依然存在,不会被置为nil——这就造成了一个很严重的问题:出现了野指针。当访问这个野指针时,指向了原地址,而原地址
是nil,所以会造成程序的crash。但是用weak来修饰的话,对象释放的时候会把指针置为nil,从而避免了野指针的出现。
那又有个疑问出现了,凭什么基本数据类型就可以使用assign。这就要扯到堆和栈的问题了,基本数据类型会被分配到栈空间,而栈空间是由系统自动管理分配和释放的,就不会造成野指针的问题。
ARC
ARC:Automatic Reference Counting ,自动引用计数器。
启用ARC后,编译器会在何时的地方帮我们插入retain/release代码。

ARC -retainable object pointer
-
block指针
-
oc对象指针
-
用attribute((NSObject))标记的对象(不常用,暂时没见过)
ARC里创建或得到对象指针的方式有五种:
-
alloc
-
new
-
copy
-
mutable
-
init
ARC的对象修饰符
-
__strong 是默认的。只要有强类型指针指向一个对象,那么该对象会一直”生存“下去。
-
__weak 表明一个不会维持所持对象生命期的引用。当没有强引用指向该对象时,弱引用会设置为nil。
-
__unsafe_unretained 指定一个引用,该引用不会维持所持对象的生命期,并且在没有强引用指向对象时也不会设置为nil。如果它所指向的对象已经被释放,那么它会成为一个野指针。
-
__autoreleasing 用以指示以引用(id*)传入的参数并在return后自动释放。
//ARC strong
{
id __strong obj =[[NSObect alloc] init];//启用了ARC,obj在出了作用域之后会自动释放。
id obj_1=[[NSObect alloc] init];//__strong是缺省值,可以不写。该句和上一句等价
}
//ARC weak
{
id __weak obj=[[NSObect alloc] init];//obj执行到下一句就会被置nil,因为没有强引用指向被创建到对象,该对象随即就会被销毁!
..
..
..
}
Retain Cycle
-
property - weak
-
block - weak,@weakify&@strongify
关于block的retain cycle问题
block什么情况下会出现retain cycle
@property(nonatomic,copy) void(^myBlock)(void);//由于self已经强持有block了
-(void)func{
self.myBlock=^{
[self doSomething]//而在这里block又强持有self,于是出现循环引用。
}
}
-(void)doSomething
{
}
方法1:解决block的retain cycle
在@weakify&@strongify出现之前用这种方式处理
@property(nonatomic,copy) void(^myBlock)(void);//self强持有block
-(void)func{
__weak typeof(self) weakSelf=self;//这里使用ARC里的对象修饰符__weak,新建一个弱引用指向self
self.myBlock=^{
__strong __typeof__(self) self_strong_ = self_weak_;//这里加一层强引用是为了保证block里面的代码未执行完的时候self不会突然被释放
[self_strong_ doSomething]//引用链中有一层weak所以不会造成retain cycle
}
}
-(void)doSomething
{
}
方法2:解决block的retain cycle
@weakify&@strongify本质是个宏,把方法一的解决方案用宏书写简化了
@property(nonatomic,copy) void(^myBlock)(void);//self强持有block
-(void)func{
@weakify(self)//定义了一个__weak修饰的self_weak_变量
self.myBlock=^{
@strongify(self)//局部定义了一个__strong的self指针指向self_weak
[self doSomething]//此时的self是局部的,是对真正的self的一个弱引用,可以愉快使用
}
}
-(void)doSomething
{
}
网友评论