一份"有点难"的iOS面试题及答案

题目来源:http://mrpeak.cn/blog/ios_interview2/

问题及答案

1.NSString 如何计算字符的个数?

NSString是UTF-16编码的, 也就是16位的unichar字符的序列. 所以, 一般遍历其每一个字符的方法就是:

for(int i=0; i<str.length; i++){
    unichar ch = [str characterAtIndex: i];
}
复制代码

对于“??”这种Emoji,是用2个16位unichar来表示,它的Unicode是U+1F44D, 用(U+D83D U+DC4D)两个字符来表示。

幸好,NSString的rangeOfComposedCharacterSequencesForRange:和rangeOfComposedCharacterSequenceAtIndex:两个方法可以用来处理这种情况.

NSRange range;
for(int i=0; i<str.length; i+=range.length){
    range = [str rangeOfComposedCharacterSequenceAtIndex:i];
    NSString *s = [str attributedSubstringFromRange:range];
}
复制代码

一次遍历一个子串, 而不是遍历一个unichar了.

URL:http://blog.csdn.net/zhouleizhao/article/details/52816744

2.PKI体系中加密和签名的区别?

加密证书和签名证书都可以用来作非对称加解密。

签名密钥对用于数据的完整性检测,保证防伪造与防抵赖,签名私钥的遗失,并不会影响对以前签名数据的验证,因此,签名私钥无须备份,因此,签名密钥不需要也不应该需要第三方来管理。

而加密密钥对用于数据的加密保护若加密私钥遗失,将导致以前的加密数据无法解密,这在实际应用中是无法接受的,加密私钥应该由可信的第三方(即通常所说的CA)来备份。

URL:http://blog.sina.com.cn/s/blog_49453d720100xran.html

3.如何自己高效实现NSUserdefault?

从使用和原理两方面讲起,使用方面,首先进行调用封装和key键管理,封装是为了使用效率,key键管理是为了方便修改和管理。

从原理方面讲,NSUserdefault 支持的数据类型有NSString、 NSNumber、NSDate、 NSArray、NSDictionary、BOOL、NSInteger、NSFloat等系统定义的数据类型。如果要进行频繁的大数据存储建议使用归档和数据库等底层更优化的方式存储。

4.解析TCP慢启动特性?

TCP在连接过程的三次握手完成后,开始传数据,并不是一开始向网络通道中发送大量的数据包,这样很容易导致网络中路由器缓存空间耗尽,从而发生拥塞。

TCP使用了一个叫慢启动门限(ssthresh)的变量,一旦cwnd>=ssthresh(大多数TCP的实现,通常大小都是65536),慢启动过程结束,拥塞避免阶段开始;

拥塞避免:cwnd的值不再指数级往上升,开始加法增加。此时当窗口中所有的报文段都被确认时,cwnd的大小加1,cwnd的值就随着RTT开始线性增加,这样就可以避免增长过快导致网络拥塞,慢慢的增加调整到网络的最佳值。

URL:https://www.cnblogs.com/edisongz/p/6986527.html

5.如何用HTTP实现长连接?

轮询:隔一段时间访问服务器,服务器不管有没有新消息都立刻返回。 设置HTTP长连接,有过期时间:

在首部字段中设置Connection:keep-alive 和Keep-Alive: timeout=60,表明连接建立之后,空闲时间超过60秒之后,就会失效。如果在空闲第58秒时,再次使用此连接,则连接仍然有效,使用完之后,重新计数,空闲60秒之后过期。

设置HTTP长连接,无过期时间: 在首部字段中只设置Connection:keep-alive,表明连接永久有效。 URL:https://www.cnblogs.com/shoren/p/http-connection.html

6.HTTP 2.0针对同一个域名的多个请求,会建立多少TCP链接?

HTTP 2.0 通信都在一个连接上完成,这个连接可以承载任意数量的双向数据流。相应地,每个数据流以消息的形式发送,而消息由一或多个帧组成,这些帧可以乱序发送,然后再根据每个帧首部的流标识符重新组装。

7.数据库建表的时候索引有什么用?

创建索引可以大大提高系统的性能。 第一,通过创建唯一性索引,可以保证数据库表中每一行数据的唯一性。

第二,可以大大加快数据的检索速度,这也是创建索引的最主要的原因。

第三,可以加速表和表之间的连接,特别是在实现数据的参考完整性方面特别有意义。

第四,在使用分组和排序子句进行数据检索时,同样可以显著减少查询中分组和排序的时间。

第五,通过使用索引,可以在查询的过程中,使用优化隐藏器,提高系统的性能。

URL:http://blog.163.com/happy_2010_zyj/blog/static/1511487562010511115227777/

8.Full Text Search为什么快?

全文索引(Full Text Search)用于模糊查询比一般的方法比如like用于模糊查询速度要快的原因是前者是用空间来换时间,在建立全文索引时主要通过分词器(lexer),将被索引的表上的那一列的所有值(即文本,要varchar等类型)分割成一个个token_text(比如,英文分词器BASIC_LEXER以空格,标点符号,_,-,等非字母数字的符号作为分割标记),而且记录这些token_text来自表里的哪些行等信息,最后将这些token_text和这些信息都写到表DR索引名I中。

有了这张表,全文索引才可以快速地查找(无论是模糊还是不模糊查找),但是该表要占据空间的。 URL:http://blog.csdn.net/caomiao2006/article/details/52075917

9.iOS下如何实现指定线程数目的线程池?

控制线程池中的线程数,来设置线程池中的线程数,也就是并发操作数。默认情况下是-1,也就是没有限制,同时运行队列中的全部操作。

[queue setMaxConcurrentOperationCount:2];
复制代码

创建线程池: 创建线程池有两种方式,第一种是OC得方式,第二种是C语言的方式。 OC版:

OC创建线程池的关键字是:NSOperationQueue OC线程池的单元是NSInvocationOperation对象,

- (void)creatThreadQueue_OC{
    NSInvocationOperation *task_1 = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(taskClick_1) object:nil];
    NSInvocationOperation *task_2 = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(taskClick_2) object:nil];
    [OC_Queue addOperation:task_1];
    [[NSOperationQueue mainQueue] addOperation:task_2];
}
复制代码

C语言创建一个线程池,C语言线程的单元式“代码块”--Block

- (void)creatThreadQueue_C{
    //serial work
    dispatch_sync(C_Queue, ^{
        [self work_1];
    });
   dispatch_sync(dispatch_get_main_queue(), ^{
        [self work_2];
    });
}
复制代码

URL:http://blog.csdn.net/u012360598/article/details/41925047

10.介绍下iOS设备获取唯一设备号的历史变迁。

从IOS5.0(2011年8月份)开始,苹果宣布将不再支持用uniqueIdentifier方法获取设备的UDID,iOS5以下是可以用的。在2013年3月21日苹果已经通知开发者:从2013年5月1日起,访问UIDIDs的程序将不再被审核通过,替代的方案是开发者应该使用“在iOS 6中介绍的Vendor或Advertising标示符”。

Vindor标示符,也是在iOS 6中新增的,跟advertisingIdentifier一样,该方法返回的是一个 NSUUID对象,可以获得一个UUID。

iOS 6中另外一个新的方法,提供了一个方法advertisingIdentifier,通过调用该方法会返回一个NSUUID实例,最后可以获得一个UUID,由系统存储着的。 URL:http://blog.csdn.net/lcg910978041/article/details/51612953

11.函数式编程当中的 first-class function 是什么意思呢?

First Class。该类型的值可以作为函数的参数和返回值,也可以赋给变量。

结构化程序设计的精髓在于模块复用和访存控制。如果说函数实现了代码复用,那么在支持First Class Function的语言中,高阶函数作为函数之间的胶水,进一步方便了函数的复用。

URL:https://www.zhihu.com/question/27460623

12.如何使用runtime hook一个class的某个方法,又如何hook某个instance的方法?

借助Runtime的Method Swizzling(方法替换)以及Associated Object(关联对象)对相关类进行扩展。

static dispatch_once_t onceToken;  
    dispatch_once(&onceToken, ^{  
        SEL selA = @selector(sendAction:to:forEvent:);  
        SEL selB = @selector(mySendAction:to:forEvent:);  
        Method methodA =   class_getInstanceMethod(self,selA);  
        Method methodB = class_getInstanceMethod(self, selB);  
        BOOL isAdd = class_addMethod(self, selA, method_getImplementation(methodB), method_getTypeEncoding(methodB));  
        if (isAdd) {  
            class_replaceMethod(self, selB, method_getImplementation(methodA), method_getTypeEncoding(methodA));  
        }else{  
            method_exchangeImplementations(methodA, methodB);  
        }  
    });  
复制代码

URL:http://blog.csdn.net/lyl123_456/article/details/52462621

13.谈下Objective C都有哪些锁机制,你一般用哪个?

1)NSLock

iOS中对于资源抢占的问题可以使用同步锁NSLock来解决,使用时把需要加锁的代码(以后暂时称这段代码为”加锁代码“)放到NSLock的lock和unlock之间,一个线程A进入加锁代码之后由于已经加锁,另一个线程B就无法访问,只有等待前一个线程A执行完加锁代码后解锁,B线程才能访问加锁代码。

2)@synchronized代码块

使用@synchronized解决线程同步问题相比较NSLock要简单一些,日常开发中也更推荐使用此方法。

3)使用GCD解决资源抢占问题

在GCD中提供了一种信号机制,也可以解决资源抢占问题(和同步锁的机制并不一样)。

4)扩展--控制线程通信

由于线程的调度是透明的,程序有时候很难对它进行有效的控制,为了解决这个问题iOS提供了NSCondition来控制线程通信(同前面GCD的信号机制类似)。

5)iOS中的其他锁

NSRecursiveLock :递归锁,有时候“加锁代码”中存在递归调用,递归开始前加锁,递归调用开始后会重复执行此方法以至于反复执行加锁代码最终造成死锁,这个时候可以使用递归锁来解决。使用递归锁可以在一个线程中反复获取锁而不造成死锁,这个过程中会记录获取锁和释放锁的次数,只有最后两者平衡锁才被最终释放。

NSDistributedLock:分布锁,它本身是一个互斥锁,基于文件方式实现锁机制,可以跨进程访问。

pthread_mutex_t:同步锁,基于C语言的同步锁机制,使用方法与其他同步锁机制类似。

URL:http://blog.csdn.net/roger_jin/article/details/45307951

14.聊下HTTP post的body体使用form-urlencoded和multipart/form-data的区别。

1)application/x-www-form-urlencoded: 窗体数据被编码为名称/值对,这是标准且默认的编码格式。当action为get时候,客户端把form数据转换成一个字串append到url后面,用?分割。当action为post时候,浏览器把form数据封装到http body中,然后发送到server。

2)multipart/form-data: multipart表示的意思是单个消息头包含多个消息体的解决方案。multipart媒体类型对发送非文本的各媒体类型是有用的。一般多用于文件上传。 multipart/form-data只是multipart的一种。目前常用的有以下这些类型(注:任何一种执行时无法识别的multipart子类型都被视为子类型"mixed") URL:http://blog.csdn.net/soonfly/article/details/52082547

15.让你设计一种机制检测UIViewController的内存泄漏,你会怎么做?

如果Controller被释放了,但其曾经持有过的子对象如果还存在,那么这些子对象就是泄漏的可疑目标。

一个小示例:子对象(比如view)建立一个对controller的weak引用,如果Controller被释放,这个weak引用也随之置为nil。那怎么知道子对象没有被释放呢?用一个单例对象每个一小段时间发出一个ping通知去ping这个子对象,如果子对象还活着就会一个pong通知。所以结论就是:如果子对象的controller已不存在,但还能响应这个ping通知,那么这个对象就是可疑的泄漏对象。

URL:http://blog.sina.com.cn/s/blog_7e6a4f740102wce9.html

16.通过[UIImage imageNamed:]生成的对象什么时候被释放?

使用imageNamed这个方法生成的UIImage对象,会在应用的bundle中寻找图片,如果找到则Cache到系统缓存中,作为内存的cache,而程序员是无法操作cache的,只能由系统自动处理,如果我们需要重复加载一张图片,那这无疑是一种很好的方式,因为系统能很快的从内存的cache找到这张图片,但是试想,如果加载很多很大的图片的时候,内存消耗过大的时候,就会会强制释放内存,即会遇到内存警告(memory warnings).

由于在iOS系统中释放图片的内存比较麻烦,所以冲易产生内存泄露。 像[[UIImageView alloc] init]还有一些其他的 init 方法,返回的都是 autorelease 对象。而 autorelease 不能保证什么时候释放,所以不一定在引用计数为 0 就立即释放,只能保证在 autoreleasepool 结尾的时候释放。

像 UIImage 还有 NSData 这种,大部分情况应该是延迟释放的,可以理解为到 autoreleasepool 结束的时候才释放。

URL:https://segmentfault.com/q/1010000004230892、http://blog.csdn.net/qq_18505715/article/details/72885498

17.applicationWillEnterForeground和applicationDidBecomeActive都会在哪些场景下被调用?举例越多越好。

1)applicationWillResignActive(将进入后台)

对应applicationWillEnterForeground(将进入前台)

程序将要失去Active状态时调用,比如按下Home键或有电话信息进来,这个方法用来

  • 暂停正在执行的任务;
  • 禁止计时器;
  • 减少OpenGL ES帧率;
  • 若为游戏应暂停游戏;

总结为一个字:停!

2)applicationDidEnterBackground(已经进入后台)

对应applicationDidBecomeActive(已经变成前台)

程序已经进入后台时调用,这个方法用来

  • 释放共享资源;
  • 保存用户数据(写到硬盘);
  • 作废计时器;
  • 保存足够的程序状态以便下次恢复; 总结为4个字:释放、保存!

URL:https://www.cnblogs.com/chenyg32/p/3873301.html

18.如何终止正在运行的工作线程?

iOS 8 以后,通过dispatch_block_cancel可以cancel掉dispatch_block_t,需要注意的是,未执行的可以用此方法cancel掉,若已经执行则cancel不掉;

如果想中断(interrupt)线程,可以使用dispatch_block_testcancel方法;值得注意的是,swift3之后DispatchWorkItem代替了dispatch_block_t,有很方便的cancel()和isCancelled可以使用。

1)使用退出标志终止线程 当run方法执行完后,线程就会退出,...return.

2)使用stop方法终止线程 thread.stop();
使用stop方法是很危险的,就象突然关闭计算机电源,而不是按正常程序关机一样,可能会产生不可预料的结果

3)使用interrupt方法终止线程 1>线程处于阻塞状态,如使用了sleep方法,将抛出一个InterruptedException例外。 2>使用while(!isInterrupted()){……}来判断线程是否被中断,线程将直接退出。

URL:http://blog.csdn.net/zhanjichun_2008/article/details/6612980、https://www.zhihu.com/question/23919984

19.穷举iOS下所有的本地持久化方案。

  • plist文件(属性列表)
  • preference(偏好设置)
  • NSKeyedArchiver(归档)
  • SQLite 3
  • CoreData URL:http://www.cocoachina.com/ios/20150720/12610.html

自己网上整理,有不对的地方还请大佬们指点~

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值