iOS面试题总结 - sacrifice的博客 - CSDN博客
1、设计模式是什么? 你知道哪些设计模式,并简要叙述?
设计模式是一种编码经验,就是用比较成熟的逻辑去处理某一种类型的事情。
1). MVC模式:Model View Control,把模型 视图 控制器 层进行解耦合编写。
2). MVVM模式:Model View ViewModel 把模型 视图 业务逻辑 层进行解耦和编写。
3). 单例模式:通过static关键词,声明全局变量。在整个进程运行期间只会被赋值一次。
4). 观察者模式:KVO是典型的通知模式,观察某个属性的状态,状态发生变化时通知观察者。
5). 委托模式:代理+协议的组合。实现1对1的反向传值操作。
6). 工厂模式:通过一个类方法,批量的根据已有模板生产对象。
2、请简述 MVC 和 MVVM 的区别
1). MVVM是对胖模型进行的拆分,其本质是给控制器减负,将一些弱业务逻辑放到VM中去处理。
2). MVC是一切设计的基础,所有新的设计模式都是基于MVC进行的改进。
3、#import 跟 #include 有什么区别? #import<> 跟 #import””有什么区别, @class 的作用,为什么要用
#import与#include的类似,都是把其后面的文件拷贝到该指令所在的地方, #import是object-c导入头文件的关键字,#include是C/c++导入头文件的关键字,使用#import导入头文件会自动只导入一次,不会重复导入。
#import <> 用于包含系统文件 #import""用于包含本项目中的文件
@class是告诉编译器某个类的声明,当执行时,才会去查看类的实现文件,可以解决头文件的相互包含。不需要向A类或A类的对象发送消息时,就可以使用该指令
4、Objective-C 的类可以多重继承么?可以实现多个接口么?Category 是什么?重写一个类的方式用继承好还是分类好?为什么?
Objective-c的类不可以有多继承,OC里面都是单继承,多继承可以用protocol委托代理来模拟实现
可以实现多个接口,可以通过实现多个接口完成OC的多重继承
Category是类别,也叫类目,用Category重写类的方法,它仅仅只对本Category有效,并不会影响到其他类和原有类的关系,如果是要在不修改原有类的基础上增加其他原有类没有的方法,就要用类目,继承是可以重写父类的方法,只是子类继承父类的方法来使用
5、frame 和 bounds 有什么不同?
frame指的是:该view在父view坐标系统中的位置和大小。(参照点是父view的坐标系统) bounds指的是:该view在本身坐标系统中的位置和大小。(参照点是本身坐标系统)
6、为什么代理要用weak?代理的delegate和dataSource有什么区别?block和代理的区别?
代理是使用weak来修饰的。1.使用weak是为了避免循环引用。2.当使用weak修饰的属性,当对象释放的时候,系统会对属性赋值nil,object-c有个特性就是对nil对象发送消息也就是调用方法,不会cash。
delegate:传递的是事件(even),代理可以让A对象通知B对象,我(A)发生的变化,前提B遵循了A的代理,并且实现了A的代理方法。
dataSource: 传递的是数据。如果A对象声明了数据源,当我们创建A对象的时候,我们就该实现数据源,来告诉A,他所需要的一些数据。例如:tableView数据源方法,需要告诉它,我要实现几组cell,每组cell多少行cell,实现的cell什么样式,什么内容
同样delegate和dataSource,都是可以使用require和optional来修饰的。
代理和Block的区别
相同点:代理和Block大多是我们都可以用来做倒序传值的。我们都得注意避免循环引用。不然我们去使用代理还是Block的时候,都需要判断它们是否实现
不同点:代理使用weak修饰,代理必须先声明方法。当我们调用代理的时候要判断是否已经实现。
block:使用的是copy来修饰,block保存的是一段代码,其实也就是一个函数。并且可以自动捕捉自动变量,如果想修改此自动变量,还必须使用__block修饰。
7、@property 中有哪些属性关键字?/ @property 后面可以有哪些修饰符?
属性可以拥有的特质分为四类:
1.原子性---- nonatomic
2.读/写属性---- readwrite(读写)readonly(只读)
3.内存管理--- strong weak assign copy retain unsafe_unretained
4.方法名--- getter setter
8、什么情况下使用weak关键字,与assign有什么不同?
a.在ARC中,在可能出现循环引用的情况下,往往要通过让其中一端使用weak来解决,比如delegate.
b.自身已经对它进行一次强引用,没有必要再强引用一次,此时也会使用weak,自定义IBOutlet控件一般也使用weak。
a.weak此特质表明该属性定义了一种“非拥有关系”,为这种属性设置新值时,既不保留新值,也不释放旧值。此特质与assign类似,然而在属性所指的对象遭到摧毁时,属性值也会被清空nil 。而assign的“设置方法”只会执行针对“纯量类型”的简单赋值操作。当assign指针所指向的内存被释放(引用计数为0),不会自动赋值nil。如果调用assign修饰的属性,会导致野指针操作,如果这个操作发生时内存还没有改变内容,依旧可以输出正确的结果,如果内容发生了改变,就会crash。
b.assign可以用非OC对象,而weak必须用于OC对象
9、Objective-C 如何对内存管理的,说说你的看法和解决方法?
Objective-C的内存管理主要有三种方式ARC(自动内存计数)、手动内存计数、内存池。
1). 自动内存计数ARC:由Xcode自动在App编译阶段,在代码中添加内存管理代码。
2). 手动内存计数MRC:遵循内存谁申请、谁释放;谁添加,谁释放的原则。
3). 内存释放池Release Pool:把需要释放的内存统一放在一个池子中,当池子被抽干后(drain),池子中所有的内存空间也被自动释放掉。内存池的释放操作分为自动和手动。自动释放受runloop机制影响。
10、Objective-C 中创建线程的方法是什么?如果在主线程中执行代码,方法是什么?如果想延时执行代码、方法又是什么?
线程创建有三种方法:使用NSThread创建、使用GCD的dispatch、使用子类化的NSOperation,然后将其加入NSOperationQueue;
在主线程执行代码,方法是 performSelectorOnMainThread
如果想延时执行代码可以用 performSelector:onThread:withObject:waitUntilDone:;
11、用@property声明的 NSString / NSArray / NSDictionary 经常使用 copy 关键字,为什么?如果改用strong关键字,可能造成什么问题?
答:用 @property 声明 NSString、NSArray、NSDictionary 经常使用 copy 关键字,是因为他们有对应的可变类型:NSMutableString、NSMutableArray、NSMutableDictionary,他们之间可能进行赋值操作(就是把可变的赋值给不可变的),为确保对象中的字符串值不会无意间变动,应该在设置新属性值时拷贝一份。
1. 因为父类指针可以指向子类对象,使用 copy 的目的是为了让本对象的属性不受外界影响,使用 copy 无论给我传入是一个可变对象还是不可对象,我本身持有的就是一个不可变的副本。
2. 如果我们使用是 strong ,那么这个属性就有可能指向一个可变对象,如果这个可变对象在外部被修改了,那么会影响该属性。
//总结:使用copy的目的是,防止把可变类型的对象赋值给不可变类型的对象时,可变类型对象的值发送变化会无意间篡改不可变类型对象原来的值。
12、Category(类别)、 Extension(扩展)和继承的区别
1. 分类有名字,类扩展没有分类名字,是一种特殊的分类。
2. 分类只能扩展方法(属性仅仅是声明,并没真正实现),类扩展可以扩展属性、成员变量和方法。
3. 继承可以增加,修改或者删除方法,并且可以增加属性。
13、我们说的OC是动态运行时语言是什么意思?
主要是将数据类型的确定由编译时,推迟到了运行时。简单来说, 运行时机制使我们直到运行时才去决定一个对象的类别,以及调用该类别对象指定方法。
14、什么时候用delete,什么时候用Notification?
Delegate(委托模式):1对1的反向消息通知功能。
Notification(通知模式):只想要把消息发送出去,告知某些状态的变化。但是并不关心谁想要知道这个。
15、什么是 KVO 和 KVC?
1). KVC(Key-Value-Coding):键值编码 是一种通过字符串间接访问对象的方式(即给属性赋值)
举例说明:
stu.name = @"张三" // 点语法给属性赋值
[stu setValue:@"张三" forKey:@"name"]; // 通过字符串使用KVC方式给属性赋值
stu1.nameLabel.text = @"张三";
[stu1 setValue:@"张三" forKey:@"nameLabel.text"]; // 跨层赋值
2). KVO(key-Value-Observing):键值观察机制 他提供了观察某一属性变化的方法,极大的简化了代码。
KVO只能被KVC触发,包括使用setValue:forKey:方法和点语法。
// 通过下方方法为属性添加KVO观察
- (void)addObserver:(NSObject *)observer
forKeyPath:(NSString *)keyPath
options:(NSKeyValueObservingOptions)options
context:(nullable void *)context;
// 当被观察的属性发送变化时,会自动触发下方方法
- (void)observeValueForKeyPath:(NSString *)keyPath
ofObject:(id)object
change:(NSDictionary *)change
context:(void *)context{}
KVC 和 KVO 的 keyPath 可以是属性、实例变量、成员变量。
16、你一般是怎么用Instruments的?
Instruments里面工具很多,常用:
1). Time Profiler: 性能分析
2). Zombies:检查是否访问了僵尸对象,但是这个工具只能从上往下检查,不智能。
3). Allocations:用来检查内存,写算法的那批人也用这个来检查。
4). Leaks:检查内存,看是否有内存泄露。
17、GCD 与 NSOperation 的区别:
GCD 和 NSOperation 都是用于实现多线程:
GCD 基于C语言的底层API,GCD主要与block结合使用,代码简洁高效。
NSOperation 属于Objective-C类,是基于GCD更高一层的封装。复杂任务一般用NSOperation实现。
18、如何用GCD同步若干个异步调用?(如根据若干个url异步加载多张图片,然后在都下载完成后合成一张整图)
// 使用Dispatch Group追加block到Global Group Queue,这些block如果全部执行完毕,就会执行Main Dispatch Queue中的结束处理的block。
// 创建队列组
dispatch_group_t group = dispatch_group_create();
// 获取全局并发队列
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_group_async(group, queue, ^{ /*加载图片1 */ });
dispatch_group_async(group, queue, ^{ /*加载图片2 */ });
dispatch_group_async(group, queue, ^{ /*加载图片3 */ });
// 当并发队列组中的任务执行完毕后才会执行这里的代码
dispatch_group_notify(group, dispatch_get_main_queue(), ^{
// 合并图片
});
19、什么是 RunLoop
从字面上讲就是运行循环,它内部就是do-while循环,在这个循环内部不断地处理各种任务。
一个线程对应一个RunLoop,基本作用就是保持程序的持续运行,处理app中的各种事件。通过runloop,有事运行,没事就休息,可以节省cpu资源,提高程序性能。
主线程的run loop默认是启动的。iOS的应用程序里面,程序启动后会有一个如下的main()函数
int main(int argc, char * argv[]) {
@autoreleasepool {
return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
}
}
20、Runtime实现的机制是什么,怎么用,一般用于干嘛
1). 使用时需要导入的头文件 <objc/message.h> <objc/runtime.h>
2). Runtime 运行时机制,它是一套C语言库。
3). 实际上我们编写的所有OC代码,最终都是转成了runtime库的东西。 比如:
类转成了 Runtime 库里面的结构体等数据类型,
方法转成了 Runtime 库里面的C语言函数,
平时调方法都是转成了 objc_msgSend 函数(所以说OC有个消息发送机制)
// OC是动态语言,每个方法在运行时会被动态转为消息发送,即:objc_msgSend(receiver, selector)。
// [stu show]; 在objc动态编译时,会被转意为:objc_msgSend(stu, @selector(show));
4). 因此,可以说 Runtime 是OC的底层实现,是OC的幕后执行者。
Runtime库里面包含了跟类、成员变量、方法相关的API。比如:
(1)获取类里面的所有成员变量。
(2)为类动态添加成员变量。
(3)动态改变类的方法实现。
(4)为类动态添加新的方法等。因此,有了Runtime,想怎么改就怎么改。
21、HTTP协议中 POST 方法和 GET 方法有那些区别?
GET用于向服务器请求数据,POST用于提交数据
GET请求,请求参数拼接形式暴露在地址栏,而POST请求参数则放在请求体里面,因此GET请求不适合用于验证密码等操作
GET请求的URL有长度限制,POST请求不会有长度限制
22、请简单的介绍下APNS发送系统消息的机制
APNS优势:杜绝了类似安卓那种为了接受通知不停在后台唤醒程序保持长连接的行为,由iOS系统和APNS进行长连接替代。
APNS的原理:
1). 应用在通知中心注册,由iOS系统向APNS请求返回设备令牌(device Token)
2). 应用程序接收到设备令牌并发送给自己的后台服务器
3). 服务器把要推送的内容和设备发送给APNS
4). APNS根据设备令牌找到设备,再由iOS根据APPID把推送内容展示
23、AFNetworking 底层原理分析
AFNetworking主要是对NSURLSession和NSURLConnection(iOS9.0废弃)的封装,其中主要有以下类:
1). AFHTTPRequestOperationManager:内部封装的是 NSURLConnection, 负责发送网络请求, 使用最多的一个类。(3.0废弃)
2). AFHTTPSessionManager:内部封装是 NSURLSession, 负责发送网络请求,使用最多的一个类。
3). AFNetworkReachabilityManager:实时监测网络状态的工具类。当前的网络环境发生改变之后,这个工具类就可以检测到。
4). AFSecurityPolicy:网络安全的工具类, 主要是针对 HTTPS 服务。
5). AFURLRequestSerialization:序列化工具类,基类。上传的数据转换成JSON格式
(AFJSONRequestSerializer).使用不多。
6). AFURLResponseSerialization:反序列化工具类;基类.使用比较多:
7). AFJSONResponseSerializer; JSON解析器,默认的解析器.
8). AFHTTPResponseSerializer; 万能解析器; JSON和XML之外的数据类型,直接返回二进制数据.对服务器返回的数据不做任何处理.
9). AFXMLParserResponseSerializer; XML解析器;
24、描述下SDWebImage里面给UIImageView加载图片的逻辑
SDWebImage 中为 UIImageView 提供了一个分类UIImageView+WebCache.h, 这个分类中有一个最常用的接口sd_setImageWithURL:placeholderImage:,会在真实图片出现前会先显示占位图片,当真实图片被加载出来后再替换占位图片。
加载图片的过程大致如下:
1.首先会在 SDWebImageCache 中寻找图片是否有对应的缓存, 它会以url 作为数据的索引先在内存中寻找是否有对应的缓存
2.如果缓存未找到就会利用通过MD5处理过的key来继续在磁盘中查询对应的数据, 如果找到了, 就会把磁盘中的数据加载到内存中,并将图片显示出来
3.如果在内存和磁盘缓存中都没有找到,就会向远程服务器发送请求,开始下载图片
4.下载后的图片会加入缓存中,并写入磁盘中
5.整个获取图片的过程都是在子线程中执行,获取到图片后回到主线程将图片显示出来
SDWebImage原理:
调用类别的方法:
1. 从内存(字典)中找图片(当这个图片在本次使用程序的过程中已经被加载过),找到直接使用。
2. 从沙盒中找(当这个图片在之前使用程序的过程中被加载过),找到使用,缓存到内存中。
3. 从网络上获取,使用,缓存到内存,缓存到沙盒
25、请简述 SOCKET/TCP/HTTP 三者的联系和区别。
1. TCP连接和HTTP连接的区别
HTTP是基于TCP的, 客户端往服务端发送一个HTTP请求时第一步就是要建立与服务端的TCP连接, 也就是先三次握手, "你好, 你好, 你好". 从HTTP1.1开始支持持久连接, 也就是一次TCP连接可以发送多次的HTTP请求.
2. TCP连接与Socket连接的区别
Socket层只是在TCP/UDP传输层上做得一个抽象接口层, 因此一个Socket连接可以基于连接, 也有可能基于UDP. 基于TCP协议的Socket连接同样需要三次握手建立连接, 是可靠的. 基于UDP协议的Socket连接不需要建立连接的过程, 不管对方能不能接收到都会发送过去, 是不可靠的, 大多数的及时通讯IM都是后者.
3. HTTP连接和Socket连接的区别
区分这两个概念是比较有意义的, 毕竟TCP看不到摸不着, HTTP与Socket是实实在在能用到的.
HTTP是短连接, Socket(基于TCP协议的)是长连接.尽管HTTP1.1开始支持持久连接, 但仍无法保证始终连接. 而Socket连接一旦建立TCP三次握手, 除非一方主动断开, 否则连接状态一直保持.
HTTP连接服务端无法主动发消息, Socket连接双方请求的发送先后限制.这点比较重要了, 因为它将决定二者分别适合应用在什么场景下. HTTP采用"请求-响应"机制, 在客户端还没发送消息给服务端钱, 服务端无法推送消息给客户端. 必须满足客户端发送消息在前, 服务端回复在后. Socket连接双方类似peer2peer的关系, 一方可以向另一方喊话.
4. 问题来了:什么时候该用HTTP, 什么时候该用Socket
这个问题的提出是自然而然的. 当你接到一个与另一方的网络通讯需求, 自然会考虑用HTTP还是Socket.
用HTTP的情况: 双方不需要时刻保持连接在线, 比如客户端资源的获取、文件上传等
用Socket的情况: 大部分及时通讯应用(QQ、微信)、聊天室、苹果APNs等
在iOS中,发HTTP请求一般用原生的NSURLConnection、NSURLSession或者开源的AFNetworking(推荐)、ASIHttpRequest(已停止更新).连接Socket连接可以用CocosAsyncSocket.