一、为什么说OC是动态语言?
答:1.动态类型: 即运行时再决定对象的类型。简单说就是id类型,任何对象都可以被id指针所指,只有在运行时才能决定是什么类型。像内置的明确的基本类型都属于静态类型(int、NSString等)。静态类型在编 译的时候就能被识别出来。所以,若程序发生了类型不对应,编译器就会发出警告。而动态类型就编译器编译的时候是不能被识别的,要等到运行时(run time),即程序运行的时候才会根据语境来识别。所以这里面就有两个概念要分清:编译时跟运行时。
2.动态绑定:基于动态类型,在某个实例对象被确定后,其类型便被确定了。该对象对应的属性和响应的消息也被完全确定,这就是动态绑定。比如我们一般向一个NSObject对象发送-respondsToSelector:或者 -instancesRespondToSelector:等来确定对象是否可以对某个SEL做出响应,而在OC消息转发机制被触发之前,对应的类 的+resolveClassMethod:和+resolveInstanceMethod:将会被调用,在此时有机会动态地向类或者实例添加新的方 法,也即类的实现是可以动态绑定的;isKindOfClass也是一样的道理。
3.动态加载:所谓动态加载就是我们做开发的时候icon图片的时候在Retina设备上要多添加一个张@2x的图片,当设备更换的时候,图片也会自动的替换。
二、讲一下MVC和MVVM,MVP?
1、MVC(Model-View-Controller)是最常见的软件架构之一。View 传送指令到 Controller, Controller 完成业务逻辑后,要求 Model 改变状态, Model 将新的数据发送到 View,用户得到反馈。
2、MVP (Model-View-Presenter)。{
(1)各部分之间的通信,都是双向的。
(2)View 与 Model 不发生联系,都通过 Presenter 传递。
(3)View 非常薄,不部署任何业务逻辑,称为"被动视图"(Passive View),即没有任何主动性,而 Presenter非常厚,所有逻辑都部署在那里。
}
3、MVVM(Model-View-ViewModel)
三、delegate 为什么要用weak修饰?
答: weak:指明该对象并不负责保持delegate这个对象,delegate这个对象的销毁由外部控制
strong:该对象强引用delegate,外界不能销毁delegate对象,会导致循环引用(Retain Cycles)
现在有A,B两个类,在A中实现了B.delegate= self。如果使用了strong修饰,就会造成A,B互相持有,当释放B时,由于A还持有B,会造成B释放不成功,释放A的时候同样会释放不成功,这样的话就造成了循环引用。使用weak修饰,weak表示A对象并不持有B,会成功释放,不会造成循环引用。
四、delegate 和 Block的区别
代理的好处:
delegate运行成本低。block成本很高的。
block出栈需要将使用的数据从栈内存拷贝到堆内存,当然对象的话就是加计数, 使用完或者block置nil后才消除;delegate只是保存了一个对象指针,直接回调,没有额外消耗。相对C的函数指针,只多做了一个查表动作。
delegate:
1.“一对一”,对同一个协议,一个对象只能设置一个代理delegate,任何人,任何对象,只要接受,只要允许,只要遵守了相关的协议,TA就可以使用代理
2.代理更注重过程信息的传输:比如发起一个网络请求,可能想要知道此时请求是否已经开始、是否收到了数据、数据是否已经接受完成、数据接收失败
block:
1.写法更简练,不需要写protocol、函数等等
2.block注重结果的传输:比如对于一个事件,只想知道成功或者失败,并不需要知道进行了多少或者额外的一些信息
3.block需要注意防止循环引用:
四、NSString为什么要用copy关键字,如果用strong会有什么问题?
可以看到,用copy修饰的name1的地址和string的地址是不一样的,用Strong修饰的name2和string的地址是一样的,所以当修改string的值的时候,name1并没有变化,name2有变化。
五、copy和MutableCopy
1.不可变对象:
NSArray * Arr1 = [NSArray arrayWithObject:@"44444444444"];
NSArray * arr1 = [Arr1 copy];
NSArray * mArr1 = [Arr1 mutableCopy];
NSLog(@"Arr1 = %p",Arr1);
NSLog(@"arr1 = %p",arr1);
NSLog(@"mArr1 = %p",mArr1);
可以发现Arr1和arr1的内存地址是一样,说明Arr1和arr1的指针指向同一块内存。Arr1和mArr1是两个独立的对象
2.可变对象:
NSMutableArray * muArr = [[NSMutableArray alloc]init];
[muArr arrayByAddingObject:@"sssssss"];
NSArray * arr = [muArr copy];
NSArray * mArr = [muArr mutableCopy];
NSLog(@"%p",muArr);
NSLog(@"%p",arr);
NSLog(@"%p",mArr);
对不可变对象进行copy和mutableCopy,得到的都是不一样的内存地址,所以这三个都是相互独立的。
3.使用copy无论原始对象是否可变,copy后的对象都是不可变的,mutableCopy后的对象都是可变的。
六、category和extension
extension看起来很像一个匿名的category,但是extension和有名字的category几乎完全是两个东西。 extension在编译期决议,它就是类的一部分,在编译期和头文件里的@interface以及实现文件里的@implement一起形成一个完整的类,它伴随类的产生而产生,亦随之一起消亡。extension一般用来隐藏类的私有信息,你必须有一个类的源码才能为一个类添加extension,所以你无法为系统的类比如NSString添加extension。
但是category则完全不一样,它是在运行期决议的。就category和extension的区别来看,我们可以推导出一个明显的事实,extension可以添加实例变量,而category是无法添加实例变量的(因为在运行期,对象的内存布局已经确定,如果添加实例变量就会破坏类的内部布局,这对编译型语言来说是灾难性的)。