1.为什么说Objective-C是一门动态的语言?
oc是由runtime实现的消息传递机制,可以动态的添加替换方法。而不是C那样传统的函数调用。类在oc中是动态创建的,然后根据runtime查出selector,method,imp等然后绑定上去,所谓的运行时绑定。
所以,方便使用swizzing method进行方法替换统一埋点。
同时,也可以用runtime运行时给分类添加属性。
用字符串映射类或者方法解耦等。
2.讲一下MVC和MVVM?
MVC就是传统的model,view,controller。model为数据模型,view提供视图展示,controller为控制器提供数据计算和视图控制。
MVC中C包括对数据处理,网络请求,并包含一些视图逻辑,过于臃肿,在此基础上提出MVVM。
MVVM中model和view与MVC中的view和model一致,多出来了viewModel,作为view和model的粘合剂,在这里进行数据的业务处理、网络请求等,这样就减轻了controller的负担。
controller就可以单纯的加载和处理页面逻辑,加载和处理viewmodel和view的关系。
可以使用ReactiveCocoa信号的来实现MVVM。(也可以使用代理)
在controller里实现视图逻辑和双向绑定(view和viewmodel的双向绑定)。
在viewmodel里提供view所需的数据变量属性,以及view点击调用的接口。在vm内部实现网络请求以及数据处理。
在view中根据vm的变量进行实时动态展示。
设计模式除了mvc,mvvm还有mvp等,都是为了解决c过于臃肿的问题。
3.为什么代理要用weak?代理的delegate和dataSource有什么区别?block和代理的区别?
使用weak避免循环引用。如果使用strong,遵循代理的这个类要持有代理,代理里也要持有这个类,会造成循环引用,所以使用weak,使用weak不增加引用计数,不再有强引用、引用计数为0时也随之释放。
delegate,代理主要是去实现他的一些方法,比如tableview滑动时做一些事这类的。
datasource,数据源主要是需要一些数据,比如tableview有多少行、每行多高这类的。
block和代理都是倒叙传值。区别在于block比较方便,可以把实现直接写在block里。不用像代理那样声明协议遵循协议指定代理再实现代理那么麻烦。
4.属性的实质是什么?包括哪几个部分?属性默认的关键字都有哪些?@dynamic关键字和@synthesize关键字是用来做什么的?
成员变量+set方法+get方法。
readwrite,atomic。值类型:assign。引用类型:strong。
@synthesize 自动生成get、set方法,重命名变量。同时get、set方法同时重写是要手动加上@synthesize name = _name
。
@@dynamic 不自动生成get、set、方法。
OC特性,主要区别和C和C++。在他们中,要分别定义成员变量以及相应的set、get方法,比较麻烦。
5.NSString为什么要用copy关键字,如果用strong会有什么问题?
如果NSString使用strong类型,那么当将一个NSMutableString这样的可变字符串赋值给NSString之后,如果可变字符串改变值,字符串也会跟着改变。这是由于浅拷贝,只拷贝了内存地址。
如果使用了copy则为深拷贝,拷贝内容被分配新的地址。这样可变字符串改变时,字符串不会跟着改变。
strong没有开辟新的内存地址,只是引用计数+1,这样数据源的数据改变,使用strong修饰的变量也会改变。浅拷贝。
copy开辟了新的内存地址,在新的内存地址上存放数据,源数据改变不会影响copy修饰的变量。为深拷贝。
所以NSString要用copy修饰,避免不小心被修改
copy会将可变深拷贝为不可变,再进行可变操作为崩溃,所以不能用来修饰mutable(可变类型),以及数组
6. 如何令自己所写的对象具有拷贝功能?
遵循NSCopying协议。
并实现copyWithZone方法。
可变 -> 不可变 (copy)
可变 -> 可变 (mutableCopy)
不可变 -> 可变 (mutableCopy)
7.为什么IBOutlet修饰的UIView也适用weak关键字
因为在xib中拖动添加控件的时候就已经加到父视图的subviews里了,已经带有强引用了,所以在于view关联时用weak也不会造成不释放。
8.nonatomic和atomic的区别?atomic是绝对的线程安全么?为什么?如果不是,那应该如何实现?
首先涉及到原子性。原子性就是如果A给B转钱,A减少1000,B增加一千,如果发生了断电等特殊情况时,操作同时取消,不会发生A钱变少B钱没变多的情况。同时成功或同时失败被称为原子性。
atomic,原子性,安全,效率低。
nonatomic,非原子性,不安全,效率高。
通常使用nonatomic,因为通常属性不需要原子性。同时atomic只是读写安全,并不是绝对保证线程安全,只是通过原子性更好的避免出错,仍需要线程锁。
atomic的实现机制。
使用atomic
修饰的话,在setter
和getter
中会使用os_unfair_lock
来加锁。锁是有限的,不同的属性读取可能用的是同一个锁。
atomic不能保证线程安全。
- 由于是在
setter
、getter
中进行的加锁,所以对于可变容器,比如@property(atomic) NSMutableArray *array
,无法保证线程安全。 - 由于是在
setter
、getter
中进行的加锁,当我们重写setter
、getter
方法时,就要依靠自己保证线程安全。
9. 进程和线程的区别?同步异步的区别?并行和并发的区别?
进程,系统运行的总称。
线程,进程的一个单位。
同步,阻塞当前线程,等待完成后继续线程
异步,不阻塞当前线程,开辟新的线线程同时进行
10.线程间通信?
主要用到在线程中dispatch_async(dispatch_get_main_queue()回到主线程刷新UI。
11.GCD的一些常用的函数?
回到主线程:dispatch_async(dispatch_get_main_queue()
创建异步线程:
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)
GCD延迟:dispatch_after
GCD只执行一次:dispatch_once
任务组:dispatch_group_t
12.如何使用队列来避免资源抢夺?
ios多线程——锁
13.数据持久化的几个方案
plist
userdefault
NSKeyedArchiver
coredata
realm
14.说一下appdelegate的几个方法?从后台到前台调用了哪些方法?第一次启动调用了哪些方法?从前台到后台调用了哪些方法?
didFinishLaunchingWithOptions 应用程序已启动
applicationDidBecomeActive 完全激活
applicationDidEnterBackground 进入后台
applicationWillEnterForeground 将进入前台
15.NSCache优于NSDictionary
NSCache在资源不足时会自动释放内存
NSCache线程安全
16.知不知道Designated Initializer?使用它的时候有什么需要注意的问题
初始化函数。alloc分配内存再使用Init初始化。
17.实现description方法能取到什么效果?
NSObject自带的方法,可以用来打印对象的内存地址。可以重写打印其属性以及我们需要的信息。
18.objc使用什么机制管理对象内存?
ARC,自动引用计数。当计数为0时释放内存。
19..block的实质是什么?
block的实质是匿名函数
20.为什么在默认情况下无法修改被block捕获的变量? __block都做了什么?
block捕获的是值内容,而非值地址。所以不能修改。
__block修饰变量则拷贝进block的是值地址,可以修改。
21.模拟一下循环引用的一个情况?block实现界面反向传值如何实现?
self持有block,block持有self,造成循环引用,在block前声明weakSelf并在block内使用weakSelf即可。
22.objc在向一个对象发送消息时,发生了什么?
根据对象的isa指针找到类对象id,在查询类对象里面的methodLists方法函数列表与SEL,如果没有找到,在沿着superClass,寻找父类,再在父类methodLists方法列表里面查询,最终找到匹配SEL,call IMP(指针函数)。
23.什么时候会报unrecognized selector错误?iOS有哪些机制来避免走到这一步?
如果找到基类NSObject都没找到,就会调用NSObject里面的方法报错。
涉及到消息转发。一共三步。
第一步:resolove动态解析
第二步:fast forwarding重定向
第三步:normal forwarding重定向
24.能否向编译后得到的类中增加实例变量?能否向运行时创建的类中添加实例变量?为什么?
前者不可以后者可以。
可以通过class_addvar和class_addmethod添加。
25.runtime如何实现weak变量的自动置nil?
当声明一个weak变量指向一个创建的对象后。实际上将创建对象的内存地址为key,将所有指向这个对象的weak变量为内容放进哈希表里。一旦对象引用计数为0,执行dealloc方法的同时,会根据这个对象的内存地址为key去哈希表里找到相应的内容并且清空。
26.给类添加一个属性后,在类结构体里哪些元素会发生变化?
instance_size :实例的内存大小
objc_ivar_list *ivars:属性列表
27.runloop是来做什么的?runloop和线程有什么关系?主线程默认开启了runloop么?子线程呢?
一般来讲线程一次只能执行一个任务,执行完就会结束。而我们需要一个机制,能随时处理消息而不退出。runloop正提供一个这样的函数,在函数内一直处于“接受消息-等待-处理”的循环中,直到循环结束。
runloop和线程的关系:如果一个线程想一直处于运行状态,就需要一个runloop。
主线程默认开启一个runloop,也就是这个runloop保证我们程序执行。子线程默认没有开启,可以获取,同时在第一次获取时创建。
28.runloop的mode是用来做什么的?有几种mode?
- kCFRunLoopDefaultMode: App的默认 Mode,通常主线程是在这个 Mode 下运行的。
- UITrackingRunLoopMode: 界面跟踪 Mode,用于 ScrollView 追踪触摸滑动,保证界面滑动时不受其他 Mode 影响。
- UIInitializationRunLoopMode: 在刚启动 App 时第进入的第一个 Mode,启动完成后就不再使用。
- GSEventReceiveRunLoopMode: 接受系统事件的内部 Mode,通常用不到。
- kCFRunLoopCommonModes: 这是一个占位的 Mode,没有实际作用。
29.为什么把NSTimer对象以NSDefaultRunLoopMode(kCFRunLoopDefaultMode)添加到主运行循环以后,滑动scrollview的时候NSTimer却不动了?
nstime对象是在NSDefaultRunLoopMode下面调用消息的,但是当我们滑动scrollview的时候,NSDefaultRunLoopMode模式就自动切换到UITrackingRunLoopMode模式下面,却不可以继续响应nstime发送的消息。所以如果想在滑动scrollview的情况下面还调用nstime的消息,我们可以把nsrunloop的模式更改为NSRunLoopCommonModes
30.项目中网络如何做信息安全?
- 使用https
2.不要传输,使用hash加密
3.请求尽量带上mac
31.main之前的过程?
编译,执行load方法。