atomic和nonatomic区别,以及作用?
atomic与nonatomic的主要区别在于系统自动生成的getter/setter方法实现不同:
atomic:系统自动生成的getter/setter方法会进行加锁操作nonatomic:系统自动生成的getter/setter方法不会进行加锁操作
atomic的局限性:不是线程安全的
- 系统生成的getter/setter方法会进行加锁操作,但这个锁仅仅保证了getter和setter方法内部赋值/读取操作的原子性
- 由于加锁的缘故,在多个线程同时访问同一个属性的getter/setter时,会按顺序执行操作
- 重要澄清 :
atomic完全不能防止对象在getter/setter被调用时被其他线程释放。它不提供任何对象生命周期的保障。要解决线程安全问题,需要依靠ARC、信号量等线程安全机制
weak 和 assign 的不同点
weak策略在属性所指的对象遭到摧毁时,系统会将weak修饰的属性对象的指针指向nil,在OC中给nil发送消息是安全的- 如果使用
assign策略,在属性所指的对象遭到摧毁时,属性对象指针仍指向原来的对象地址,产生野指针,此时给此对象发送消息容易造成程序崩溃 assign可以用于修饰非OC对象(基本数据类型),而weak必须用于OC对象
ARC 下,不显式指定任何属性关键字时,默认的关键字都有哪些?
- 基本数据类型:
atomic, readwrite, assign - 普通的 OC 对象:
atomic, readwrite, strong
怎么用 copy 关键字?
NSString、NSArray、NSDictionary等经常使用copy关键字,是因为它们有对应的可变类型:NSMutableString、NSMutableArray、NSMutableDictionary。为确保对象中的属性值不会无意间变动,应该在设置新属性值时拷贝一份,保护其封装性block也经常使用copy关键字。在MRC下,方法内部的block默认在栈区,使用copy可以把它放到堆区- 更新说明 :在ARC环境下,编译器会自动地将作为属性被
strong或copy修饰的block从栈拷贝到堆。因此,在ARC下使用strong或copy对于block的效果相同,但Apple的文档和编码惯例仍然推荐使用copy
说一下OC的反射机制
- OC的反射机制主要基于OC的动态语言特性
- 系统Foundation框架提供了一些方法反射的API
- 我们可以通过这些API执行将字符串转为SEL等操作
- 由于OC语言的动态性,这些操作都发生在运行时
什么是僵尸对象?
- 已经被销毁的对象(不能再使用的对象),内存已经被回收的对象
野指针
- 指向僵尸对象(不可用内存/已经释放的内存地址)的指针
数组copy后里面的元素会复制一份新的吗
- 不会,数组的浅拷贝(copy)只复制数组容器本身,数组里面存储的是之前对象的地址引用,不会创建新的对象实例
OC中的NSInteger 和int 有什么区别
- 在32位操作系统时,NSInteger 等价于 int(32位)
- 在64位操作系统时,NSInteger 等价于 long(64位)
NSMutableDictionary 中使用setValueForKey 和 setObjectForKey有什么区别?
- 根据官方文档说明:一般情况下,给NSMutableDictionary发送
setValue仍然是调用setObject方法,如果参数value为nil,则会调用removeObject移除这个键值对 setObjectForKey是NSMutableDictionary特有的,value不能为nil,否则会崩溃setValueForKey是KVC的方法,key必须是字符串类型,而setObject的key可以是任意类型
面向对象的三大特性:
-
封装 隐藏对象的属性和实现细节,仅对外提供公共访问方式,将变化隔离,便于使用,提高复用性和安全性
-
继承 提高代码复用性;建立类之间的关系;子类可以拥有父类的所有成员变量和方法;继承是多态的前提
-
多态 父类或接口定义的引用变量可以指向子类或具体实现类的实例对象,提高程序的拓展性
什么是多态?
- 核心定义:多态在面向对象语言中指同一个接口有多种不同的实现方式。在OC中,多态是不同对象对同一消息的不同响应方式
- 子类通过重写父类的方法来改变同一方法的实现,体现多态性
- 实现方式:通过父类类型的指针指向子类的对象,在运行时根据对象的实际类型调用正确的方法实现
- 多态就是某一类事物的多种形态,继承是多态的前提
什么是分类?
- 分类:在不修改原有类代码的情况下,为类添加方法
- Category可以为类扩展方法,或者通过运行时关联属性。Category底层结构是一个结构体,内部存储结构体的名字、所属类的信息、对象方法和类方法列表、协议、属性信息
- 通过Runtime加载某个类的所有Category数据
- 把所有Category的方法、属性、协议数据合并到一个大数组中,后面参与编译的Category数据会在数组的前面
- 重要说明:运行时将分类的方法合并到主类中,后编译的分类方法会出现在方法列表前部。当消息发送时,运行时会按顺序查找方法,因此分类中的方法会覆盖主类中的同名方法
如何实现多继承?
重要说明:OC不支持像C++那样的直接多继承,但可以通过以下方式实现类似效果:
- 消息转发机制 :通过
forwardingTargetForSelector:或forwardInvocation:将消息转发给其他对象 - 协议:定义多个协议,实现"多接口"而非真正的多继承
- 组合模式:持有多个其他类的实例,通过方法转发来复用功能
- 类别:只能为已有类添加方法,无法实现真正的多继承
为什么说OC是一门动态语言?
- 动态语言:指程序在运行时可以改变其结构,新的函数可以被引进,已有的函数可以被删除等结构上的变化
- 动态类型语言:类型的检查是在运行时做的
OC的动态特性体现在三个方面:
- 动态类型:最终判定该类的实例类型是在运行期间
- 动态绑定:在运行时确定调用的方法
- 动态加载:在运行期间加载需要的资源或可执行代码
动态绑定
- 动态绑定将调用方法的确定推迟到运行时。OC可以先跳过编译,到运行的时候才动态地添加函数调用,在运行时才决定要调用什么方法,需要传什么参数进去
- 在编译时,方法的调用并不和代码绑定在一起,只有在消息发送出来之后,才确定被调用的代码。通过动态类型和动态绑定技术,实现真正的运行时多态
动态语言和静态语言
- 动态类型语言:数据类型的检查是在运行时做的。用动态类型语言编程时,不用给变量指定数据类型,该语言会在第一次赋值给变量时,在内部记录数据类型
- 静态类型语言:数据类型的检查是在运行前(如编译阶段)做的
关于二维数组的说明
OC中没有原生的二维数组语法,但可以通过NSArray或NSMutableArray中嵌套另一个NSArray来模拟和实现二维数组的功能,这在实践中是普遍和有效的做法