iOS经典面试题大全2021(二)(附答案)
(iOS面试资料大全)
36、 简述ARC的实现原理。它在什么时机插入retain/release?
ARC:自动引用计数。它会在对象创建或者消亡的时候自动插入retain/release。达到自动管理内存的目的。
37、 Framework与Library的区别?动态库与静态库的区别?
library与Framework的区别:
在iOS中,Library 仅能包含编译后的代码,即 .a 文件。
但一般来说,一个完整的模块不仅有代码,还可能包含.h 头文修的、.nib 视图文件、图片资源文件、说明文档。(像 UMeng 提供的那些库,集成时,要把一堆的文件拖到Xcode中,配置起来真不是省心的事。
Framework 作为 Cocoa/Cocoa Touch 中使用的一种资源打包方式,可以上述文件等集中打包在一起,方便开发者使用(就像Bundle)。
静态库与动态库的区别:
简单的说,静态链接库是指模块被编译合并到应用中,应用程序本身比较大,但不再需要依赖第三方库。运行多个含有该库的应用时,就会有多个该库的Copy在内存中,冗余。
动态库可以分开发布,在运行时查找并载入到内存,如果有通用的库,可以共用,节省空间和内存。同时库也可以直接单独升级,或作为插件发布。
38、 什么是runloop?
一般来说,一个线程一次只能执行一个任务,执行完成后线程就会退出,如果我们需要一个机制,让线程能随时处理事件但并不退出。代码逻辑如下:
function loop() {
initialize();
do {
var message = get_next_message();
process_message(message);
} while(message != quit)
}
这种模型我们通常称之为EventLoop(事件循环)。RunLoop实际上是一个对象,这个对象管理了其需要处理的事件和消息。并提供了一个入口函数来执行上面EventLoop逻辑。在OSX/iOS系统中,提供了两个这样的对象:NSRunLoop和CFRunLoopRef。
CFRunLoopRef是在CoreFoundation框架内,它提供了纯C函数的API,所有这些API都是线程安全的。
NSRunLoop是基于CFRunLoopRef的封装,提供了面向对象的API,这些API不是线程安全的。
苹果不允许直接创建RunLoop,只提供了两个自动获取的函数:CFRunLoopGetMain()和CFRunLoopGetCurrent()。
线程和RunLoop之间是一一对应的。
39、#include与#import的区别?#import与@class的区别?
“#include"与”#import"功能一样,都是导出头文件。只是#import不会引起交叉编译,可以确保头文件只导入一次。#import会包含这个类的所有信息。包括实例变量和方法,而@class只是告诉编译器,它后面声明的名称是类的名称,至于类的定义,后面会告诉你。使用#import编译效率高,可以防止相互包含的编译错误。
40、Static与const的区别?
const表示只读的意思,只在声明中使用。
static一般有2个作用,规定作用域和存储方法。对于局部变量,static规定其为静态存储区,每次调用的初始值为上一次调用的值,调用结束后存储空间不释放。
对于全局变量,如果以文件划分作用域的话,此变量只在当前文件可见,对于static函数也是在当前模块内函数可见。
41、简述GET请求与POST请求的区别。
(1)POST 需要明确制定方法 GET不需要 ,并且默认就是GET方法,并且GET有缓存,POST没有缓存
(2)GET的参数放在URL的后面,并且第一个参数用?拼接,后面的从第二个参数开始,直到最后一个,如果有多个,用&分割;POST 的参数放在请求体里面,并且第一个参数,不用,后面从第二开始,直到最后,如果有多个,用&分割;
(3)GET 一般用于获取数据,POST向服务器提交数据用到
(4)GET的参数是暴漏在地址栏的,不安全;POST的参数隐藏在请求体里面,相对安全一点;
(5)GET请求没有请求体,POST请求有请求体。
(6)GET请求提交数据受浏览器限制,1k,POST请求理论上无限制。
42、属性用__block修饰时在内存中会发生什么变化?
__block的作用就是编译器会给你创建一个函数,你可以通过这个函数修改block捕获变量的值。
43、谈谈block与函数的区别。
block可以写在方法里面,函数需要写在方法外面。block可以访问方法中的局部变量。
44、你了解runloop吗?它有几种模式?简要的说下它的应用场景。
runloop模式:
Default:
NSDefaultRunLoopMode(Cocoa)、kCFRunLoopDefaultMode(CoreFoundation)
Connection:
NSConnectionReplyMode
Modal:
NSModalPanelRunLoopMode
Event tracking:
NSEventTrackingRunLoopMode
Common modes:
NSRunLoopCommonModes(Cocoa)、kCFRunLoopCommonModes(CoreFoundation)
应用场景:
(1)使用端口或自定义输入源与其他线程通信。
(2)在线程中使用计时器
(3)使用任意的performSelector方法
(4)保持线程去执行一个周期任务。
45、你工作中用到的版本管理工具是什么?
用的是git工具来进行版本管理。
46、你用过git工具吗?用过哪些常见的命令?
git init,git add, git commit,git merge,git branch,git checkout,git pull,git push等
47、CoreAnimation常用的动画有哪些类型?
所有的核心动画的动画类都从CAAnimation类继承而来。CAAnimationGroup组动画,CATransition转场动画,CABasicAnimation:基础动画,CAKeyframeAnimation关键帧动画。
48、GCD中系统提供了几种queue?
两种:DispatchSerialQueue、DispatchConcurrentQueue。
49、二叉搜索树的概念及时间复杂度是多少?
O(n)
50、block中的weak self,是任何时候都需要加的么?
不一定,可加可不加。将block置nil也可以打破循环引用。
51、GCD的queue,main queue中执行的代码,一定是在main thread么?
是的。一定是在main thread。
52、你在使用数据库的过程中有没有遇到过问题?如何解决?
遇到过多线程操作数据库读写死锁问题,采用fmdb中提供的回滚的方式解决
53、简述iOS中的沙盒机制。
iOS中的沙盒机制是一种安全体系,它规定了应用程序只能在为该应用创建的文件夹读取文件,不可以访问其他地方的内容。所有非代码文件都保存在这个地方。如图片,声音,属性列表及文本文件等。
(1)每个应用程序都在自己的沙盒内
(2)不能随意跨越自己的沙盒去访问别的应用程序沙盒的内容
(3)应用程序向外请求或者接收数据都需要经过权限认证。
沙盒目录结构这种,因为应用是在沙箱(sandbox)中的,在文件读写权限上受到限制,只能在几个目录下读写文件:
Documents:应用中用户数据可以放在这里,iTunes备份和恢复的时候会包括此目录
tmp:存放临时文件,iTunes不会备份和恢复此目录,此目录下文件可能会在应用退出后删除
Library:存储程序的默认设置或其他状态信息。
Library/Caches:存放缓存文件,iTunes不会备份此目录,此目录下文件不会在应用退出删除
54、字符串为什么要用copy修饰?
是为了防止mutablestring被无意中修改,NSMutableString是NSString的子类。因此NSString指针可以持有NSMutableString对象。
55、nonatomic与atomic有什么区别?
atomic是Objective-C使用的一种线程保护技术,它是为了防止写操作在未完成的时候被另外一个线程读取。从而造成数据错误。这种机制是非常耗费系统资源的,所以在iphone这种小的移动设备上,如果没有使用多线程间的通讯编程。建议使用nonatomic。
默认的访问器是原子操作,就是说在多线程环境下,解析的访问器提供一个对属性安全访问,从获取器得到的返回值或者通过设置器设置的值可以一次完成,即便是多线程也在对其进行访问,如果不指定nonatomic ,在自己管理内存的环境中,解析的访问器保留并自动释放保留的值,如果是指定了nonatomic,访问器只是简单的返回一个值。
56、@synthesize与@dynamic的区别?
@synthesize:如果你没有手动实现setter方法和getter方法,编译器会自动为帮你生成setter方法和getter方法。
@dynamic:告诉编译器属性的setter和getter方法由用户自己实现,不自动生成。如果一个属性声明为@dynamic var,又没有提供setter和getter方法,编译的时候不会有问题,如果程序中运行到person.name = newName;或newName=person.name时候就会导致程序崩溃。因为”unrecognized selector sent to instance …”这就是动态绑定。
57、@property(copy)NSMutableArray *array;这句代码有什么问题?如果有请简述原因;
(1)添加、删除、修改数组内的元素的时候,程序会因为找不到对应的方法而崩溃,因为copy就是复制一个不可变的NSArray对象。
(2)没有使用nonatomic属性修饰符,默认是 atomic修饰,这样会严重影响性能。
58、NSString *str = @“hello world!”与NSString *str = [[NSString alloc] initWithString:@"hello world!”];在内存管理上有什么区别?
在MRC中,前者表示,你不持有这个对象,所以不需要手动管理其内存。后者意味着你持有这个字符串,需要自己手动管理内存,对其进行释放。
59、对于语句NSString*obj = [[NSData alloc] init]; obj在编译时和运行时分别是什么类型的对象?
编译时是NSString类型对象,运行时时NSData类型对象
首先,声明NSString*testObject是告诉编译器,obj是一个指向某个Objective-C对象的指针,因为不管指向的是什么类型的对象,一个指针所占的内存空间都是固定的,所以这里声明称任何类型的对象,最终生成的可执行代码都是没有区别的。这里限定了NSString只不过是告诉编译器,请把obj当做一个NSString来检查,如果后面调用了非NSString的方法,会产生警告,接着,你创建了一个NSData对象,然后把这个对象所在的内存地址保存在obj里。那么运行时,obj指向的内存空间就是一个NSData对象。你可以把obj当做一个NSData对象来用。
60、self.name=object与name=object在内存管理上有什么区别?
前者通过调用setter方法设置值,后者是普通的赋值操作。
61、为什么property声明中只有”copy”特性而没有“mutableCopy”特性?
这是由于当声明property为"copy"特性时,系统会自动根据receiver的特点决定使用copy(已含retain的情况)还是mutableCopy。
62、Objective-C中id与void*有什么区别?id与instancetype有什么区别?nil、null、NULL三者有什么区别?
Objective-C中id与void*区别:
id是指向OC类对象的指针,它可以声明为任何类对象的指针,当在OC中使用id时,编译器会假定你知道,id指向哪个类的对象。与void不同,void编译器不知道也不假定指向任何类型的指针。
id与instancetype区别:
id返回的是id类型,instancetype返回的是所在类的类型。
相同点是同样都是作为方法的返回类型。
区别:
(1) instancetype可以返回和方法所在类相同类型的对象,id只能返回未知类型的对象。
(2) instancetype只能作为返回值,id可以作为参数。
nil、Nil、NULL三者区别:
nil是一个指向不存在的对象指针(对象空指针)。Nil是指向不存在的类指针(类空指针)。NULL指向其他类型的空指针。NSNull在集合对象中,表示空值的对象。
63、数据解析方式有几种?他们有什么区别?你项目中采用的是哪种数据解析方式?
JSON和XML。
64、用预处理指令#define声明一个常数,用以表明1年中有多少秒(忽略闰年问题)
“#define SECONDS_PER_YEAR(606024*365)UL”
65、写一个”标准"宏MIN ,这个宏输入两个参数并返回较小的一个。
“#define MIN(X,Y) ((X)>(Y)?(X):(Y))”
66、+load和+initialize 的区别是什么?
+initialize:第一次初始化这个类之前被调用,我们用它来初始化静态变量。
+load方法会在加载类的时候就被调用,也就是iOS应用启动的时候,就会加载所有的类。
+initialize方法类似一个懒加载,如果没有使用这个类,系统默认不会去调用这个方法,且默认只加载一次。
如果是在类别中,+load方法会全都执行,但是类别中的load方法会后于类中的方法,+initialize方法会覆盖类中的方法,只执行一个。
+initialize的调用发生在+init方法之前。子类会去调用父类的+initialize方法。
67、new和alloc/init的区别
概括来说,new和alloc/init在功能上几乎是一致的,分配内存并完成初始化。
差别在于,采用new的方式只能采用默认的init方法完成初始化。
而采用alloc的方式可以用其他定制的初始化方法。
68、如果让你设计接口与API,应该注意点什么?
(1)用前缀避免命名空间冲突
(2)提供“全能初始化方法”
(3)实现description方法
(4)尽量使用不可变对象
(5)使用清晰而协调的命名方法
(6)为私有方法名加前缀
(7)错误处理
(8)实现NSCopying协议。
69、你在项目中用过懒加载吗?能简单的说说懒加载吗?
懒加载又称为延迟加载。写的是其get方法。如果是懒加载的话则一定要注意先判断是否已经有了,如果没有那么再去进行实例化。
好处是不必将创建对象的代码全部写在viewDidLoad方法中,代码的可读性更强。每个控件的getter方法中分别负责各自的实例化处理,代码彼此之间的独立性强,松耦合。
70、进程和线程的区别与联系。
进程是个静态的容器,里面容纳了很多个线程,线程是一系列方法的线性执行路径。
71、简述内存分区情况。
栈区:存放函数的参数值,局部变量的值等。由编译器自动分配释放
堆区:由程序员分配释放。程序员如果不释放,则程序结束时可能由系统回收
全局区:全局变量和静态变量是存储在一块的。初始化的全局变量和静态变量在一块区域,未初始化的全局变量和未初始化的静态变量在另一块区域。程序结束后由系统释放。全局区可分为未初始化全局区:.bbs段和初始化全局区:data段。
常量区:存放常量字符串,程序结束后由系统释放
代码区:存放函数体的二进制代码。
72、队列与栈有什么区别?
栈:限定仅在表尾进行插入或删除操作的线性表。表尾是栈顶,表头是栈底。它又称后进先出线性表。
队列:是一种先进先出的线性表。它只允许在表的一端进行插入,而在另一端删除元素。
73、Objective-C中多线程的编程方式有几种
pthread、NSThread、NSOperation、GCD。
74、Objective-C运行时(runtime)机制了解吗?简单的说说对象调用方法的过程。
对象调用方法的过程:(Objective-C Runtime)
(1)在对象类的dispatch table中尝试找到该消息。如果找到了,跳到相应的函数IMP去执行实现代码
(2)如果没有找到,Runtime会发送+resolveInstanceMethod: 或者 +resolveClassMethod: 尝试去resolve这个消息
(3)如果resolve方法返回NO,Runtime就发送 -forwardingTargetForSelector: 允许你把这个消息转发给另一个对象;
(4)如果没有新的目标对象返回,Runtime 就会发送 -methodSignatureForSelector: 和 -forwardInvocation: 消息。你可以发送 -invokeWithTarget: 消息来手动转发消息或者发送 -doesNotRecognizeSelector: 抛出异常。