在iOS开发过程中,虽然我们能顺利地把项目写出来,甚至能够独立完成一个项目,但是有一些理论知识点我们会用就是很懵懂的了解,还是不能够深入理解其原理。本文是我在闲暇之际总结的一些简单的,常用的,但是还不够深入理解的小知识(精通者可以绕行了😂)!
1、iOS属性修饰符详解
常用的属性修饰符都有:assign,weak,copy,strong
assign:主要用于修饰基本数据类型(如NSInteger和CGFloat)和C数据类型(如int,float,double,char等),这些数值主要存在于栈上
weak:表示指向但不拥有该对象,其修饰的对象引用计数不会增加。无需手动设置,该对象会自行在内存中销毁。在ARC环境下,为避免循环引用,通常用来修饰delegate属性。
copy:建立一个索引计数为1的对象,然后释放旧对象。一般用于修饰有可变对应类型的不可变对象上,如NSString,NSArray,NSDictionary。也可以用来修饰block。
strong:表示指向并拥有该对象,其修饰的对象引用计数会增加1,相当于MRC下的retain。一般用于修饰自定义对象,UI控件对象,NSMutableString,NSMutableArray,NSMutableDictionary。
【copy与strong】
copy一般修饰NSString,NSArray,NSDictionary,block等。
strong一般修饰NSMutableString,NSMutableArray,NSMutableDictionary,还有自定义对象、UI控件对象等。
copy和strong 实际在的差异就在于setter的生成的方式不一样1
2
3
4//copy
- (void)setName:(NSString *)name {
_name = [name copy];
}
1 | //strong |
1、NSString为什么用copy而不用strong?
当源对象是NSString时,使用copy或strong没有区别。当源对象是NSMutableString时,strong属性只是增加了对象的引用计数,而copy属性是执行了一次深拷贝,所以strong属性的字符串会跟随源对象的改变而改变,copy属性的字符串不会随着源对象改变。一般我们定义了一个属性都不希望它能改变,所以一般都用copy关键字。
2、NSArray为什么用copy而不用strong?
正如NSString一样,当源对象是不可变的NSArray时,使用copy或strong没有区别。当源对象是NSMutableArray时,如果使用strong修饰,当NSMutableString改变时,NSArray这个不可变的数组也会改变。所以我们用copy修饰NSArray。
3、NSDictionary为什么用copy而不用strong?
同NSString和NSArray一样的道理。
4、NSMutableString为什么用strong而不用copy?
我们都知道不管是可变还是不可变类型的对象copy之后都返回不可变类型的对象,如果用copy修饰NSMutableString会返回一个不可变的NSString类型,当调用一些改变该字符串的方法(如[self.mString appendString:@”aa”])时,由于调用方法的对象是不可变类型会造成crash。所以一般可变类型对象用strong修饰,NSMutableArray,NSMutableDictionary同样的道理。
【strong与weak】
strong:强引用,相当于MRC下的retain,会使对象的引用计数+1,只要引用存在,对象就不会被销毁,当所有强引用消除时,对象才能被释放。
weak:弱引用,相当于MRC下的assign,不会使对象的引用计数+1,被weak修饰的对象随时可被系统销毁和回收。常用于修饰delegate。
2、iOS程序的生命周期
3、UIViewController的生命周期
1 | 方法的调用顺序: |
4、Runtime
参考白开水写的一篇文章iOS模式详解—「runtime&runloop面试、工作」看我就🐒了^_^.,该文章介绍的非常详细!
【runtime概念】
- Objective-C是基于C的,它为C添加了面向对象的特性。它将很多静态语言在编译和链接时期做的事放到了runtime运行时来处理,可以说runtime是我们Objective-C幕后工作者。
- runtime是一套纯C(C和汇编)写的API。而OC就是运行时机制,也就是在运行时候的一些机制,其中最主要的是消息机制。
- 对于C语言,在编译的时候会决定调用哪个函数。
- 对于OC,在编译的时候并不能决定真正调用哪个函数,只有在真正运行的时候才会根据函数的名称找到对应的函数来调用
- 事实证明:在编译阶段,OC可以调用任何函数,即使这个函数并未实现,只要声明过就不会报错,只有当运行的时候才会报错,这是因为OC是运行时动态调用的。而C语言调用未实现的函数就会报错。
【runtime消息机制】
消息机制原理:对象根据方法编号SEL去映射表查找对应的方法实现。
每个类都有一个方法列表,存放着方法的名字和方法实现的映射关系,每个方法编号(selector
)对应着一个函数指针(IMP
),而函数指针就指向对应的方法实现。
在Objective-C中调用一个方法,其实是向一个对象发送消息,runtime就会根据对象的isa指针找到该对象对应的类或父类的方法列表,然后对象根据方法编号从方法列表中找到对应的函数指针(IMP
),从而找到方法实现。
【runtime常见作用】
- 动态交换两个方法的实现(method swizzling)
- 动态添加属性
- 实现字典转模型的自动转换
- 发送消息
- 动态添加方法
- 拦截并替换方法
- 实现 NSCoding 的自动归档和解档
5、分类与类扩展
首先要弄清楚什么是分类(类别),什么是类扩展1
2
3
4//分类(Category)
@interface NSObject (Category)
- (void)doSomething;
@end
1 | //类扩展(Extension) |
【分类(Category)】
- 可以在不修改原类的基础上,为一个类扩展方法(主要用于给系统自带的类扩展方法),如果方法名与原类的方法名冲突了,则会优先执行分类的方法,因为分类具有更高的优先级。不可以删除原方法。
- 分类只能添加方法,不能添加属性和成员变量。
- 如果分类中声明了一个属性,那么分类只会生成这个属性的set和get方法的声明,不会实现。
【类扩展(Extension)】
- 类扩展是分类的一个特例(有时被称为匿名分类),一般写在
.m
文件中 - 可以为一个类添加私有的成员变量、属性、方法,并且添加的方法必须要实现。
【分类和类扩展的区别】
- 类扩展能添加方法、成员变量和属性;分类只能添加方法,不能添加属性和成员变量(如果添加了属性,系统不会自动实现setter和getter方法,需要我们通过runtime实现)
- 类扩展添加的方法必须要实现,分类可以不实现
- 类扩展可以写在
.m
文件中,也可以写在.h
文件中,写在.m
中的是私有的,写在.h
中的是公有的。
6、iOS远程推送的流程原理
1、应用程序注册苹果服务器的消息推送
2、iOS从苹果服务器获取到deviceToken,应用程序接收deviceToken
3、应用程序将接收到的deviceToken发送给程序的Push服务端
4、Push服务端向苹果服务器发送消息
5、苹果服务器将消息发送给iPhone手机的应用程序