# iOS基础 # iOS面试题二

如果你不知道你接下来需要补充学习哪一部分知识,做点面试题吧。

接上文

61、NStimer准吗?谈谈你的看法?如果不准该怎样实现一个精确的NSTimer?

1.不准

2.不准的原因如下:

1、NSTimer加在main runloop中,模式是NSDefaultRunLoopMode,main负责所有主线程事件,例如UI界面的操作,复杂的运算,这样在同一个runloop中timer就会产生阻塞。

2、模式的改变。主线程的 RunLoop 里有两个预置的 Mode:kCFRunLoopDefaultMode 和 UITrackingRunLoopMode。

当你创建一个 Timer 并加到 DefaultMode 时,Timer 会得到重复回调,但此时滑动一个ScrollView时,RunLoop 会将 mode 切换为 TrackingRunLoopMode,这时 Timer 就不会被回调,并且也不会影响到滑动操作。所以就会影响到NSTimer不准的情况。

PS:DefaultMode 是 App 平时所处的状态,rackingRunLoopMode 是追踪 ScrollView 滑动时的状态。

方法一:

1、在主线程中进行NSTimer操作,但是将NSTimer实例加到main runloop的特定mode(模式)中。避免被复杂运算操作或者UI界面刷新所干扰。

self.timer = [NSTimer timerWithTimeInterval:1 target:self selector:@selector(showTime) userInfo:nil repeats:YES];

[[NSRunLoop currentRunLoop] addTimer:self.timer forMode:NSRunLoopCommonModes];

2、在子线程中进行NSTimer的操作,再在主线程中修改UI界面显示操作结果;

- (void)timerMethod2 {
NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(newThread) object:nil];
[thread start];
}
- (void)newThread
{
@autoreleasepool
{
[NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(showTime) userInfo:nil repeats:YES];
[[NSRunLoop currentRunLoop] run];
}
}
总结:

一开始的时候系统就为我们将主线程的main runloop隐式的启动了。

在创建线程的时候,可以主动获取当前线程的runloop。每个子线程对应一个runloop

方法二:

使用示例

使用mach内核级的函数可以使用mach_absolute_time()获取到CPU的tickcount的计数值,可以通过”mach_timebase_info”函数获取到纳秒级的精确度 。然后使用mach_wait_until(uint64_t deadline)函数,直到指定的时间之后,就可以执行指定任务了。

关于数据结构mach_timebase_info的定义如下:

struct mach_timebase_info {uint32_t numer;uint32_t denom;};
#include
#include
static const uint64_t NANOS_PER_USEC = 1000ULL;
static const uint64_t NANOS_PER_MILLISEC = 1000ULL * NANOS_PER_USEC;
static const uint64_t NANOS_PER_SEC = 1000ULL * NANOS_PER_MILLISEC;
static mach_timebase_info_data_t timebase_info;
static uint64_t nanos_to_abs(uint64_t nanos) {
return nanos * timebase_info.denom / timebase_info.numer;
}
void example_mach_wait_until(int seconds)
{
mach_timebase_info(&timebase_info);
uint64_t time_to_wait = nanos_to_abs(seconds * NANOS_PER_SEC);
uint64_t now = mach_absolute_time();
mach_wait_until(now + time_to_wait);
}
方法三:直接使用GCD替代!
 
 cgd timer
 

self.gcdTime = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, dispatch_get_global_queue(0, 0));
// 开始时间支持纳秒级别
dispatch_time_t start = dispatch_time(DISPATCH_TIME_NOW, (int64_t)2 * NSEC_PER_SEC);
// 2秒执行一次
uint64_t dur = (uint64_t)(2.0 * NSEC_PER_SEC);
// 最后一个参数是允许的误差,即使设为零,系统也会有默认的误差
dispatch_source_set_timer(self.gcdTime, start, dur, 0);
// 设置回调
dispatch_source_set_event_handler(self.gcdTime, ^{
    NSLog(@"---%@---%@",[NSThread currentThread],self);
});


取消定时器:dispatch_cancel(self.gcdTimer);

62、你知道哪些设计模式,并简要叙述?

1). MVC模式:Model View Control,把模型 视图 控制器 层进行解耦合编写。
2). MVVM模式:Model View ViewModel 把模型 视图 业务逻辑 层进行解耦和编写。
3). 单例模式:通过static关键词,声明全局变量。在整个进程运行期间只会被赋值一次。
4). 观察者模式:KVO是典型的通知模式,观察某个属性的状态,状态发生变化时通知观察者。
5). 委托模式:代理+协议的组合。实现1对1的反向传值操作。
6). 工厂模式:通过一个类方法,批量的根据已有模板生产对象。

63、import 跟 #include 有什么区别,@class呢,#import<> 跟 #import”” 有什么区别?

1. #import是Objective-C导入头文件的关键字,#include是C/C++导入头文件的关键字,使用#import头文件会自动只导入一次,不会重复导入。
2. @class告诉编译器某个类的声明,当执行时,才去查看类的实现文件,可以解决头文件的相互包含。
3. #import<> 用来包含系统的头文件,#import””用来包含用户头文件。

64、tableView的重用机制能简单说一下么?

cell池
visibleCells 当前显示的cells

reusableTableCells 保存重用的cells

dequeueReusableCellWithIdentifier 获取重用cell

超出屏幕的时候 更新 reusableTableCells
reload的时候  更新 reusableTableCells

reusableTableCells为空的话  reloadRowsAtIndex 也会更新

65、写一个线程安全的单例模式 - 保证线程安全的方式

加锁和GCD栅栏,队列组相关知识

66、在手势对象基础类UIGestureRecognizer的常用子类手势类型中哪两个手势发生后,响应只会执行一次?

UITapGestureRecognizer,UISwipeGestureRecognizer是一次性手势,手势发生后,响应只会执行一次。

67、自定义库要注意些什么

抽象和封装,方便使用。

首先是对问题有充分的了解,比如构建一个文件解压压缩框架,从使用者的角度出发,只需关注发送给框架一个解压请求,框架完成复杂文件的解压操作,

并且在适当的时候通知给使用者,如解压完成、解压出错等。

在框架内部去构建对象的关系,通过抽象让其更为健壮、便于更改。其次是API的说明文档。

68、对于Objective-C,你认为它最大的优点和最大的不足是什么

最大的优点是它的运行时特性,不足是没有命名空间,对于命名冲突,可以使用长命名法或特殊前缀解决,如果是引入的第三方库之间的命名冲突,可以

对项目buildsetting里的other linker flags进行修改(第三方静态库引用者修改)

Bulding Setting里设置的other linker flags添加的有-Objc,而-Objc得作用就是将加载的静态库中的分类一并加载到程序的可执行文件,如果不添加这个参数,很有可能会出现selector not recognized问题,主要是找不到分类定义的方法。
-Objc添加后就会出现多个静态库定义同样的方法、全局变量等,然后就会出现上面的问题duplicate symbol。

69、NSOperationQueue

你用过NSOperationQueue么?如果用过或者了解的话,你为什么要使用NSOperationQueue,实现了什么?请描述它和G.C.D的区别和类似的地方(提示:可以从两者的实现机制和适用范围来描述)。

使用NSOperationQueue用来管理子类化的NSOperation对象,控制其线程并发数目。GCD和NSOperation都可以实现对线程的管理,区别是 NSOperation和NSOperationQueue是多线程的面向对象抽象。

项目中使用NSOperation的优点是NSOperation是对线程的高度抽象,在项目中使用它,会使项目的程序结构更好,子类化NSOperation的设计思路,是具有面向对象的优点(复用、封装),使得实现是多线程支持,而接口简单,建议在复杂项目中使用。

项目中使用GCD的优点是GCD本身非常简单、易用,对于不复杂的多线程操作,会节省代码量,而Block参数的使用,会是代码更为易读,建议在简单项目中使用。

70、程序内存分区

程序内存分区
以下是比较常用的五分区方式,当然也不排除网上有其他的分区方式。


栈
栈的大小在编译时就已经确定了,一般是2M;栈是一块从高到低地址的连续区域,存放临时变量和执行函数时的内存等。栈内存分配分为动态和静态,静态如自动变量(局部变量)等,动态如alloc等。

堆
堆是从低到高地址的不连续区域,类似链表;用来存放malloc或new申请的内存。

全局/静态
存放静态/全局变量;全局区细分为未初始化/初始化区。

常量
存放常量;程序中使用的常量会到常量区获取。
可以看看这个例子来理解一下。

...int a;//a在全局未初始化区int a = 10;//a在全局初始化区 10在常量区static int a = 10;//a在静态区 10在常量区//程序入口int main(...) {   int a = 10;//a在栈区 10在常量区
   static int a = 10;//a在静态区 10在常量区
   char *a = (char *)malloc(10); //a在栈区 malloc后的内存在堆区
   ...
}
代码
存放二进制代码,运行程序就是执行代码,代码要执行就要加载进内存(RAM运行内存)。

71、指针函数 / 函数指针 / Block

指针函数

C语言的概念;本质是函数,返回指针。

char *fun() {    char *p = "";    return p;
}

函数指针

C语言的概念;本质是指针,指向函数。

int fun(int a,int b) {    return a + b;
}int (*func)(int,int);
func = fun;
func(1,2);//3

Block

OC语言的概念;表示一个代码块,OC中视为对象;挺像C函数指针的。

//typedeftypedef int (^SumBlock)(int a,int b);
SumBlock sumBlock = ^(int a,int b) {    return a + b;
};
sumBlock(1,2);//3//普通
 int (^sumBlock)(int a,int b) = ^(int a,int b) {    return a + b;
};
sumBlock(1,2);//3

72、iOS类和结构体有什么区别

1:类指针赋值时只是复制了地址,结构体是复制内容;
2:类不能有同名同参数个数的方法,结构体可以;
3:结构体方法实现编译时就确定了,类方法实现可动态改变;
4:内存分配不一样,结构体在栈,类在堆;
5:结构体可以多重继承,类只能单继承。

73、线程安全方法

线程安全:多线程环境下保证数据的完整性。

队列

把操作放入队列线性执行,可用GCD和NSOperationQueue。

锁/信号量

用锁/信号量形成操作互斥。

让操作原子化

让操作原子执行,系统提供了一些原子执行的方法。

了解更多

iOS-线程安全

74、NSOperationQueue和GCD区别联系

区别

NSOperationQueue没有串行/并发队列,但可以设置最大并发数;
NSOperationQueue支持方法和block,GCD只支持block;
NSOperationQueue可以暂停/取消操作;
NSOperationQueue支持更多的功能,比如KVO和自定义操作;
NSOperationQueue可以设置操作的优先级,GCD只能设置队列的优先级。

联系

提供的功能是相似的;
NSOperationQueue是GCD的封装。

75、对程序性能的优化你有什么建议?

1.使用复用机制
2.尽可能设置 View 为不透明
3.避免臃肿的 XIB 文件
4.不要阻塞主线程
5.图片尺寸匹配 UIImageView,避免巨大图片
6.选择合适的容器
8.View 的复用和懒加载机制
9.缓存  服务器的响应信息(response)、 图片、计算值。比如:UITableView 的 row heights。
10.关于图形绘制、减少离屏渲染(设置圆角和阴影的时候可以选用绘制的方法)
11.处理 Memory Warnings
在 AppDelegate 中实现 - [AppDelegate applicationDidReceiveMemoryWarning:] 代理方法。
在 UIViewController 中重载 didReceiveMemoryWarning 方法。
监听 UIApplicationDidReceiveMemoryWarningNotification 通知。
12.复用高开销的对象
14.优化 UITableView
通过正确的设置 reuseIdentifier 来重用 Cell。
尽量减少不必要的透明 View。
尽量避免渐变效果、图片拉伸和离屏渲染。
当不同的行的高度不一样时,尽量缓存它们的高度值。
如果 Cell 展示的内容来自网络,确保用异步加载的方式来获取数据,并且缓存服务器的 response。
使用 shadowPath 来设置阴影效果。
尽量减少 subview 的数量,对于 subview 较多并且样式多变的 Cell,可以考虑用异步绘制或重写 drawRect。
尽量优化 - [UITableView tableView:cellForRowAtIndexPath:] 方法中的处理逻辑,如果确实要做一些处理,可以考虑做一次,缓存结果。
选择合适的数据结构来承载数据,不同的数据结构对不同操作的开销是存在差异的。
对于 rowHeight、sectionFooterHeight、sectionHeaderHeight 尽量使用常量。
15.选择合适的数据存储方式
在 iOS 中可以用来进行数据持有化的方案包括:
NSUserDefaults。只适合用来存小数据。
XML、JSON、Plist 等文件。JSON 和 XML 文件的差异在「选择正确的数据格式」已经说过了。
使用 NSCoding 来存档。NSCoding 同样是对文件进行读写,所以它也会面临必须加载整个文件才能继续的问题。
使用 SQLite 数据库。可以配合 FMDB 使用。数据的相对文件来说还是好处很多的,比如可以按需取数据、不用暴力查找等等。
使用 CoreData。也是数据库技术,跟 SQLite 的性能差异比较小。但是 CoreData 是一个对象图谱模型,显得更面向对象;SQLite 就是常规的 DBMS。
16.减少应用启动时间
快速启动应用对于用户来说可以留下很好的印象。尤其是第一次使用时。
保证应用快速启动的指导原则:
尽量将启动过程中的处理分拆成各个异步处理流,比如:网络请求、数据库访问、数据解析等等。
避免臃肿的 XIB 文件,因为它们会在你的主线程中进行加载。重申:Storyboard 没这个问题,放心使用。
注意:在测试程序启动性能的时候,最好用与 Xcode 断开连接的设备进行测试。因为 watchdog 在使用 Xcode 进行调试的时候是不会启动的。
17.使用 Autorelease Pool (内存释放池)
18.imageNamed 和 imageWithContentsOfFile,imageName会缓存图片

76、NSURLConnection 和NSURLSession 的区别是 么? NSURLProtocol是做什么的?

1.下载
NSURLConnection下载文件时,先是将整个文件下载到内存,然后再写入到沙盒,如果文件比较大,就会出现内存暴涨的情况。
而使用NSURLSessionDownloadTask下载文件,会默认下载到沙盒中的tem文件中,不会出现内存暴涨的情况,但是在下载完成后会把tem中的临时文件删除,需要在初始化任务方法时,在completionHandler回调中增加保存文件的代码
2.请求方法的控制
NSURLConnection实例化对象,实例化开始,默认请求就发送(同步发送),不需要调用start方法。而cancel可以停止请求的发送,停止后不能继续访问,需要创建新的请求。
NSURLSession有三个控制方法,取消(cancel)、暂停(suspend)、继续(resume),暂停以后可以通过继续恢复当前的请求任务。
使用NSURLSession进行断点下载更加便捷.
NSURLSession的构造方法(sessionWithConfiguration:delegate:delegateQueue)中有一个NSURLSessionConfiguration类的参数可以设置配置信息,其决定了cookie,安全和高速缓存策略,最大主机连接数,资源管理,网络超时等配置。NSURLConnection不能进行这个配置,相比较与NSURLConnection依赖与一个全局的配置对象,缺乏灵活性而言,NSURLSession有很大的改进

77、如果项目开始容错处理没做?如何防止拦截潜在的崩溃?

例:

1、category给类添加方法用来替换掉原本存在潜在崩溃的方法。

2、利用runtime方法交换技术,将系统方法替换成类添加的新方法。

3、利用异常的捕获来防止程序的崩溃,并且进行相应的处理。

总结:

1、不要过分相信服务器返回的数据会永远的正确。

2、在对数据处理上,要进行容错处理,进行相应判断之后再处理数据,这是一个良好的编程习惯。

78、容错处理你们一般是注意哪些?

在团队协作开发当中,由于每个团队成员的水平不一,很难控制代码的质量,保证代码的健壮性,经常会发生由于后台返回异常数据造成app崩溃闪退的情况,为了避免这样的情况项目中做一些容错处理,显得格外重要,极大程度上降低了因为数据容错不到位产生崩溃闪退的概率。

例如:

1.字典

2.数组;

3.野指针;

4.NSNull   @"{\"value\": null}";  这种json解析出来的时候,NSNull如果去执行方法,就会 unrecognized selector

等~

79、内存泄漏可能会出现的几种原因,聊聊你的看法?

第一种可能:第三方框架不当使用;

第二种可能:block循环引用;

第三种可能:delegate循环引用;

第四种可能:NSTimer循环引用 如 和 VC的循环引用

第五种可能:非OC对象内存处理

第六种可能:地图类处理

第七种可能:大次数循环内存暴涨



追问一:非OC对象如何处理?

非OC对象,其需要手动执行释放操作例:CGImageRelease(ref),否则会造成大量的内存泄漏导致程序崩溃。

其他的对于CoreFoundation框架下的某些对象或变量需要手动释放、C语言代码中的malloc等需要对应free。

80、常用锁有以下几种:

1.@synchronized 关键字加锁

2. NSLock 对象锁

3. NSCondition

4. NSConditionLock 条件锁

5. NSRecursiveLock 递归锁

6. pthread_mutex 互斥锁(C语言)

7. dispatch_semaphore 信号量实现加锁(GCD)

8. OSSpinLock

9.pthread_rwlock

10.POSIX Conditions

11.os_unfair_lock

追问一:自旋和互斥对比?

自旋锁和互斥锁

相同点:都能保证同一时间只有一个线程访问共享资源。都能保证线程安全。

不同点:

互斥锁:如果共享数据已经有其他线程加锁了,线程会进入休眠状态等待锁。一旦被访问的资源被解锁,则等待资源的线程会被唤醒。

自旋锁:如果共享数据已经有其他线程加锁了,线程会以死循环的方式等待锁,一旦被访问的资源被解锁,则等待资源的线程会立即执行。

自旋锁的效率高于互斥锁。

使用自旋锁时要注意:

由于自旋时不释放CPU,因而持有自旋锁的线程应该尽快释放自旋锁,否则等待该自旋锁的线程会一直在哪里自旋,这就会浪费CPU时间。

持有自旋锁的线程在sleep之前应该释放自旋锁以便其他可以获得该自旋锁。内核编程中,如果持有自旋锁的代码sleep了就可能导致整个系统挂起。

使用任何锁都需要消耗系统资源(内存资源和CPU时间),这种资源消耗可以分为两类:

1.建立锁所需要的资源

2.当线程被阻塞时所需要的资源

追问二:用C/OC/C++,任选其一,实现自旋或互斥?口述即可!

cpp实现:


两种锁的加锁原理:

互斥锁:线程会从sleep(加锁)——>running(解锁),过程中有上下文的切换,cpu的抢占,信号的发送等开销。

自旋锁:线程一直是running(加锁——>解锁),死循环检测锁的标志位,机制不复杂。

81、优化你是从哪几方面着手

一、首页启动速度

启动过程中做的事情越少越好(尽可能将多个接口合并)

不在UI线程上作耗时的操作(数据的处理在子线程进行,处理完通知主线程刷新节目)

在合适的时机开始后台任务(例如在用户指引节目就可以开始准备加载的数据)

尽量减小包的大小

优化方法:

量化启动时间

启动速度模块化

辅助工具(友盟,听云,Flurry)

二、页面浏览速度

json的处理(iOS 自带的NSJSONSerialization,Jsonkit,SBJson)

数据的分页(后端数据多的话,就要分页返回,例如网易新闻,或者 微博记录)

数据压缩(大数据也可以压缩返回,减少流量,加快反应速度)

内容缓存(例如网易新闻的最新新闻列表都是要缓存到本地,从本地加载,可以缓存到内存,或者数据库,根据情况而定)

延时加载tab(比如app有5个tab,可以先加载第一个要显示的tab,其他的在显示时候加载,按需加载)

算法的优化(核心算法的优化,例如有些app 有个 联系人姓名用汉语拼音的首字母排序)

三、操作流畅度优化:

Tableview 优化(tableview cell的加载优化)

ViewController加载优化(不同view之间的跳转,可以提前准备好数据)

四、数据库的优化:

数据库设计上面的重构

查询语句的优化

分库分表(数据太多的时候,可以分不同的表或者库)

五、服务器端和客户端的交互优化:

客户端尽量减少请求

服务端尽量做多的逻辑处理

服务器端和客户端采取推拉结合的方式(可以利用一些同步机制)

通信协议的优化。(减少报文的大小)

电量使用优化(尽量不要使用后台运行)

82、怎么防止别人动态在你程序生成代码?怎么防止反编译?

(这题是听错了面试官的意思)

面试官意思是怎么防止别人反编译你的app?

1.本地数据加密

iOS应用防反编译加密技术之一:对NSUserDefaults,sqlite存储文件数据加密,保护帐号和关键信息

2.URL编码加密

iOS应用防反编译加密技术之二:对程序中出现的URL进行编码加密,防止URL被静态分析

3.网络传输数据加密

iOS应用防反编译加密技术之三:对客户端传输数据提供加密方案,有效防止通过网络接口的拦截获取数据

4.方法体,方法名高级混淆

iOS应用防反编译加密技术之四:对应用程序的方法名和方法体进行混淆,保证源码被逆向后无法解析代码

5.程序结构混排加密

iOS应用防反编译加密技术之五:对应用程序逻辑结构进行打乱混排,保证源码可读性降到最低

84、你理解的多线程?

1.可能会追问,每种多线程基于什么语言?

2.生命周期是如何管理?

3.你更倾向于哪种?追问至现在常用的两种你的看法是?

第一种:pthread

.特点:

1)一套通用的多线程API

2)适用于Unix\Linux\Windows等系统

3)跨平台\可移植

4)使用难度大

b.使用语言:c语言

c.使用频率:几乎不用

d.线程生命周期:由程序员进行管理

第二种:NSThread

a.特点:

1)使用更加面向对象

2)简单易用,可直接操作线程对象

b.使用语言:OC语言

c.使用频率:偶尔使用

d.线程生命周期:由程序员进行管理

第三种:GCD

a.特点:

1)旨在替代NSThread等线程技术

2)充分利用设备的多核(自动)

b.使用语言:C语言

c.使用频率:经常使用

d.线程生命周期:自动管理

第四种:NSOperation

a.特点:

1)基于GCD(底层是GCD)

2)比GCD多了一些更简单实用的功能

3)使用更加面向对象

b.使用语言:OC语言

c.使用频率:经常使用

d.线程生命周期:自动管理

多线程的原理

同一时间,CPU只能处理1条线程,只有1条线程在工作(执行)

多线程并发(同时)执行,其实是CPU快速地在多条线程之间调度(切换)

如果CPU调度线程的时间足够快,就造成了多线程并发执行的假象

思考:如果线程非常非常多,会发生什么情况?

CPU会在N多线程之间调度,CPU会累死,消耗大量的CPU资源

每条线程被调度执行的频次会降低(线程的执行效率降低)

多线程的优点

能适当提高程序的执行效率

能适当提高资源利用率(CPU、内存利用率)

多线程的缺点

开启线程需要占用一定的内存空间(默认情况下,主线程占用1M,子线程占用512KB),如果开启大量的线程,会占用大量的内存空间,降低程序的性能

线程越多,CPU在调度线程上的开销就越大

程序设计更加复杂:比如线程之间的通信、多线程的数据共享

你更倾向于哪一种?

倾向于GCD:

GCD

技术是一个轻量的,底层实现隐藏的神奇技术,我们能够通过GCD和block轻松实现多线程编程,有时候,GCD相比其他系统提供的多线程方法更加有效,当然,有时候GCD不是最佳选择,另一个多线程编程的技术

NSOprationQueue 让我们能够将后台线程以队列方式依序执行,并提供更多操作的入口,这和 GCD 的实现有些类似。

这种类似不是一个巧合,在早期,MacOX

与 iOS 的程序都普遍采用Operation

Queue来进行编写后台线程代码,而之后出现的GCD技术大体是依照前者的原则来实现的,而随着GCD的普及,在iOS 4 与 MacOS X

10.6以后,Operation Queue的底层实现都是用GCD来实现的。

那这两者直接有什么区别呢?

1.    GCD是底层的C语言构成的API,而NSOperationQueue及相关对象是Objc的对象。在GCD中,在队列中执行的是由block构成的任务,这是一个轻量级的数据结构;而Operation作为一个对象,为我们提供了更多的选择;

2.    在NSOperationQueue中,我们可以随时取消已经设定要准备执行的任务(当然,已经开始的任务就无法阻止了),而GCD没法停止已经加入queue的block(其实是有的,但需要许多复杂的代码);

3.    NSOperation能够方便地设置依赖关系,我们可以让一个Operation依赖于另一个Operation,这样的话尽管两个Operation处于同一个并行队列中,但前者会直到后者执行完毕后再执行;

4.    我们能将KVO应用在NSOperation中,可以监听一个Operation是否完成或取消,这样子能比GCD更加有效地掌控我们执行的后台任务;

5.    在NSOperation中,我们能够设置NSOperation的priority优先级,能够使同一个并行队列中的任务区分先后地执行,而在GCD中,我们只能区分不同任务队列的优先级,如果要区分block任务的优先级,也需要大量的复杂代码;

6.    我们能够对NSOperation进行继承,在这之上添加成员变量与成员方法,提高整个代码的复用度,这比简单地将block任务排入执行队列更有自由度,能够在其之上添加更多自定制的功能。

总的来说,Operation

queue

提供了更多你在编写多线程程序时需要的功能,并隐藏了许多线程调度,线程取消与线程优先级的复杂代码,为我们提供简单的API入口。从编程原则来说,一般我们需要尽可能的使用高等级、封装完美的API,在必须时才使用底层API。但是我认为当我们的需求能够以更简单的底层代码完成的时候,简洁的GCD或许是个更好的选择,而Operation

queue 为我们提供能更多的选择。

倾向于:NSOperation

NSOperation相对于GCD:

1,NSOperation拥有更多的函数可用,具体查看api。NSOperationQueue 是在GCD基础上实现的,只不过是GCD更高一层的抽象。

2,在NSOperationQueue中,可以建立各个NSOperation之间的依赖关系。

3,NSOperationQueue支持KVO。可以监测operation是否正在执行(isExecuted)、是否结束(isFinished),是否取消(isCanceld)

4,GCD 只支持FIFO 的队列,而NSOperationQueue可以调整队列的执行顺序(通过调整权重)。NSOperationQueue可以方便的管理并发、NSOperation之间的优先级。

使用NSOperation的情况:各个操作之间有依赖关系、操作需要取消暂停、并发管理、控制操作之间优先级,限制同时能执行的线程数量.让线程在某时刻停止/继续等。

使用GCD的情况:一般的需求很简单的多线程操作,用GCD都可以了,简单高效。

从编程原则来说,一般我们需要尽可能的使用高等级、封装完美的API,在必须时才使用底层API。

当需求简单,简洁的GCD或许是个更好的选择,而Operation queue 为我们提供能更多的选择。

85、SD原理以及最大支持多少个下载数?

6

86、runtime动态创建一个类,需要注意什么?

了解一些如何动态构建类

87、有一个很长字符串,你用什么算法搜索到abc的位置?

1、暴力匹配

2、KMP查找

3、后缀树

88、代码文件编译生成过程,编译和链接有什么区别,链接做了什么事情

将预处理生成的文件,经过词法分析、语法分析、语义分析以及优化后编译成若干个目标模块。可以理解为将高级语言翻译为计算机可以理解的二进制代码,即机器语言。

由链接程序将编译后形成的一组目标模块以及它们所需要的库函数链接在一起,形成一个完整的载入模型。链接主要解决模块间的相互引用问题。分为地址和空间分配,符号解析和重定位几个步骤。

在编译阶段生成目标文件时,会暂时搁置那些外部引用,而这些外部引用就是在链接时进行确定的,链接器在链接时,会根据符号名称去相应模块中寻找对应符号。待符号确定之后,链接器会重写之前那些未确定的符号的地址,这个过程就是重定位。链接一般分为静态链接、载入时动态链接以及运行时动态链接三种。

89、用C语言实现一个通知流程,说思路即可!


90、A B 线程执行到一半去执行C线程,用OC和C各自怎么实现!

wait notify


dispatch_wait

dispatch_notify

91、快排的原理

选定一个基准数,左右根据基准数进行调控,小的往基准数左边放,小的往右边放,递归执行

92、C语言中strlen和sizeof的区别

sizeof是求数据类型所占的空间大小,而strlen是求字符串的长度

93、推送的原理

1、 注册:为应用程序申请消息推送服务。此时你的设备会向APNs服务器发送注册请求。
2、 APNs服务器接受请求,并将deviceToken返给你设备上的应用程序
3、客户端应用程序将deviceToken发送给后台服务器程序,后台接收并储存。
4、 后台服务器向APNs服务器发送推送消息
5、 APNs服务器将消息发给deviceToken对应设备上的应用程序

94、一个页面可以由几个控制器共同管理吗


95、项目上线或者版本迭代,有过被拒吗?是什么原因?怎么解决?


99、请说明并比较以下关键词:atomic, nonatomic

atomic修饰的对象会保证setter和getter的完整性,任何线程对其访问都可以得到一个完整的初始化后的对象。

因为要保证操作完成,所以速度慢。它比nonatomic安全,但也并不是绝对的线程安全,例如多个线程同时调用set和get就会导致获得的对象值不一样。绝对的线程安全就要用关键词synchronized。

atomic只是get set线程安全,不代表就一定线程安全了

nonatomic修饰的对象不保证setter和getter的完整性,所以多个线程对它进行访问,它可能会返回未初始化的对象。正因为如此,它比atomic快,但也是线程不安全的。

100、你平时做过什么有技术难点的东西,然后怎么解决的

异步绘制的问题

性能优化

项目优化

代码优化

自动化打包

地图、视频


写一套对应的VC内存泄露检查机制,控件子线程调用的检查机制

101、聊一聊你之前公司的项目


MVC架构,分为,基础库(基础组件、网络请求、基础category)层、中间层(路由层、网络扩展层)、业务层、展示层

除开独立性高的业务,其他的业务层和展示层在主工程,基础层和中间层在pod资源中


Swift、OC混编项目,需要兼顾Swift和OC带来的编译问题,加入Swift后,新业务都使用Swift开发,尽量少耦合老代码。

使用pod为项目管理工具、fastlane为自动打包工具

分发系统式 基于ruby和bash脚本写的内部自动化打包分发系统

102、Swift和OC混编遇到了什么问题

1、编译速度问题 5分钟变为 10分钟

2、经常丢失断点、丢失提示、llbd打印信息错误等

这种情况,请仔细检查你的桥接文件:项目名-Bridging-Header,是否导入了第三方库。若导入了第三方库,则该库是否是以Cocoapods来管理的,比如AFNetWorking是通过 Cocoapods 管理的,那么在桥接文件中,你应该

@import AFNetWorking;

而不是 import "AFNetWorking.h",或者以这种#import导入该三方的其他文件


3、命名空间的问题

103、Swift 引入后 编译优化的一些思考

1. 尽可能的移除pch中的文件、XX-Swift.h文件千万不要图方便放到pch文件中,不然每次编译都需要全局编译

2. 尽可能的减少Objective-C与Swift的混编,减小bridge文件的大小、通过模块化,实现OC与Swift之间的隔离 通过路由的方式进行模块通信,降低耦合度,路由中间件也可以减少业务中头文件的频繁交叉、繁复引用,降低耦合性

3. 模块头文件引用以@import or import <> 库引用的方式

4. 通过中间件减少业务中头文件的交叉、繁复引用,降低耦合性

5. 通过将第三方库、基础组件二进制化减少编译时间,把很少改动或者基本不会改的库编译成二进制framework

6. 组件化的时候注意组件之间的依赖关系

- 业务组件尽可能不依赖业务组件,如果依赖关系过强,就需要考虑是否业务拆分有问题
- 业务组件只依赖基础组件与第三方库
- 基础组件不依赖业务组件
- 基础组件尽量不依赖基础组件 

104、项目优化的一些思考

项目的优化分为编译优化 和 运行优化


编译优化指的是 优化方向是优化我们的开发过程,例如编译速度,代码效率,迭代效率,扩展性等

运行优化指的是 优化方向是app的运行,例如,列表流畅度、交互体验、网络延时等等


编译优化:

Swift编译速度慢的原因:

1、本身方法实现耗时太多:在xcode中开启编译时长检查,方法编译时间超出设置值就会有黄色警告

2、过多的编译器类型检查:例如过多的optation 类型

3、头文件的引用问题,尽可能的移除pch中的文件、XX-Swift.h文件千万不要图方便放到pch文件中,不然每次编译都需要全局编译

4、swift工程引用OC pod库  不需要通过桥文件 直接import对应的库名称,也尽量少在bridge文件中对OC库的头文件进行引用,影响Xcode编译效率,同时会导致lldb调试问题和断点问题

5、 pod库太多:把一些稳定的 不需要变更的库,打成二进制包


懒加载的使用

105、iOS系统框架介绍

image

107、如何拦截AFNetworking,我希望在请求发出去之前添加一些头部信息

runtime覆盖request方法,但是很蠢

108、日志上报,错误日志上报,业界有哪些方法 案例

exception catch

信号异常 catch

109、一个app进入后台之后如何唤起

app没死可以通过通知

app已死可以通过VoIP

110、如果没有API 没有百度,你要怎么解决一个问题,有实际处理过类似情况么,比如把一个1M的文件尽可能的压缩


110、100个随机数字,想要找到最大值,时间复杂度是?

O(n)

111、数据库都有哪些类型

112、iOS虚拟内存的使用

115、什么是ABI?

应用程序二进制接口,应用程序与操作系统之间,一个应用和它的库之间或者应用的组成部分之间的低接口。

API 表示的时源代码和库之间的接口,ABI允许编译好的目标代码在使用贱人ABI的系统中无需改动就能运行

116、REST、HTTP、JSON是什么?

RESTful api Representational State Transfer 资源表现层状态转化架构

(1)每一个URI代表一种资源;
(2)客户端和服务器之间,传递这种资源的某种表现层;
(3)客户端通过四个HTTP动词,对服务器端资源进行操作,实现"表现层状态转化"。

117、delegate解决了什么问题,Notification与它有什么不同?

delegate  一对一的通信原理,完成消息回调

Notification 是一对多,与对象之间无需建立直接关系

118、LLVM与Clang的区别?

Clang 是编译器前端

Clang 的作用是 语法、语义分析器,生成中间代码

LLVM是编译器后端

LLVM的作用是代码优化器和后端生成目标程序

从宏观上来说,LLVM包含了Clang

119、Class、objc的区别是什么?

objc为实例对象,表示的时通过类构建的一个实例本身,实例对象是一个objc_object 类型的结构体,包含一个 Class类型的isa属性 用于表明其所属的类

Class为类对象,表示的是类本身

120、不通过继承,代码复用(共享)的方式有哪些

protocol 协议

extension 扩展 

runtime

122、在一个app中间有一个button,在你手触摸屏幕点击后,到这个button收到点击事件,中间发生了什么

响应链大概有以下几个步骤

1. 设备将touch到的UITouch和UIEvent对象打包, 放到当前活动的Application的事件队列中
2. 单例的UIApplication会从事件队列中取出触摸事件并传递给单例UIWindow
3. UIWindow使用hitTest:withEvent:方法查找touch操作的所在的视图view

RunLoop这边我大概讲一下

1. 主线程的RunLoop被唤醒
2. 通知Observer,处理Timer和Source 0
3. Springboard接受touch event之后转给App进程中
4. RunLoop处理Source 1,Source1 就会触发回调,并调用_UIApplicationHandleEventQueue() 进行应用内部的分发。
5. RunLoop处理完毕进入睡眠,此前会释放旧的autorelease pool并新建一个autorelease pool

参考

持久化方式学习整理

App生命周期知识学习整理

线程知识整理

事件响应链

运行时、消息转发相关

block知识整理

UIWindow、UIApplication

专题(持续更新)

iOS开发基础

iOS开发进阶

Swift学习

推荐阅读更多精彩内容

  • Swift1> Swift和OC的区别1.1> Swift没有地址/指针的概念1.2> 泛型1.3> 类型严谨 对...
    cosWriter阅读 3,256评论 0 12
  • *面试心声:其实这些题本人都没怎么背,但是在上海 两周半 面了大约10家 收到差不多3个offer,总结起来就是把...
    Dove_iOS阅读 19,989评论 40 450
  • OC语言基础 1.类与对象 类方法 OC的类方法只有2种:静态方法和实例方法两种 在OC中,只要方法声明在@int...
    奇异果好补阅读 2,853评论 0 10
  • 最全的iOS面试题及答案 iOS面试小贴士 ———————————————回答好下面的足够了-----------...
    编程新视野阅读 712评论 4 10
  • iOS面试小贴士 ———————————————回答好下面的足够了------------------------...
    不言不爱阅读 572评论 0 7