iOS 面试题累计(零)

由于一系列的原因,近期开始面试了,针对面试常问中的问题做了一些总结,以及收录了一些问题。

一、总结

1.1、@property

先思索下面几个问题

delegate 属性为什么使用 weak ?
xib/storybard连接的对象为什么使用weak?
字符串  为什么使用copy?
Block 为什么使用 copy?
  • delegate 属性为什么使用 weak? 防止循环引用的。
  • 对于 xib/storybard连接的对象为什么使用weak? 因为控件他爹( view.superview )已经揪着它的小辫了( strong reference ),你( viewController )眼瞅着( weak reference )就好了。
  • 对于字符串为什么使用copy? 通常都是使用copy的方式。虽然使用strong也没有没有问题,但是事实上在开发中都会使用copy。为什么这么做?因为对于字符串,我们希望是一次内容的拷贝,外部修改也不会影响我们的原来的值,而且NSString类遵守了NSCopying, NSMutableCopying, NSSecureCoding协议。
  • Block 为什么使用 copy? block一开始是放在栈上的,只有copy后才会放到堆上

@Property是声明属性的语法,它可以快速方便的为实例变量创建存取器,并允许我们通过点语法使用存取器。

  • 存取器(accessor):指用于获取和设置实例变量的方法。用于获取实例变量值的存取器是getter,用于设置实例变量值的存取器是setter

@property等同于在.h文件中声明实例变量的get/set方法,@synthesize等同于在.m文件中实现实例变量的get/set方法。使用@property和synthesize创建存取器要比手动声明两个存取方法(gettersetter)更简单。而且我们在使用属性时可以使用点语法赋值或取值,语法更简单,更符合面向对象编程。

@property还有一些关键字,它们都是有特殊作用的,比如上述代码中的nonatomicstrong。我把它们分为三类,分别是:原子性存取器控制内存管理

原子性

  • atomic(默认):atomic意为操作是原子的,意味着只有一个线程访问实例变量。atomic是线程安全的,至少在当前的存取器上是安全的。
  • nonatomicnonatomicatomic刚好相反。表示非原子的,可以被多个线程访问。它的效率比atomic快。但不能保证在多线程环境下的安全性,在单线程和明确只有一个线程访问的情况下广泛使用。

存取器控制

  • readwrite(默认):readwrite是默认值,表示该属性同时拥有settergetter
  • readonlyreadonly表示只有getter没有setter

内存管理

  • assign(默认):assign用于值类型,如intfloatdoubleNSIntegerCGFloat等表示单纯的复制。还包括不存在所有权关系的对象,比如常见的delegate
  • retain:在setter方法中,需要对传入的对象进行引用计数加1的操作。简单来说,就是对传入的对象拥有所有权,只要对该对象拥有所有权,该对象就不会被释放。如下代码所示:
 - (void)setName:(NSString *)_name
 { 
     //首先判断是否与旧对象一致,如果不一致进行赋值。
     //因为如果是一个对象的话,进行if内的代码会造成一个极端的情况:当此name的retain为1时,使此次的set操作让实例name提前释放,而达不到赋值目的。 
      if ( name != _name){
             [name release];
             name = [_name retain];
       } 
  }
  • strongstrong是在iOS引入ARC的时候引入的关键字,是retain的一个可选的替代。表示实例变量对传入的对象要有所有权关系,即强引用.
  • weak:在setter方法中,需要对传入的对象不进行引用计数加1的操作。简单来说,就是对传入的对象没有所有权,当该对象引用计数为0时,即该对象被释放后,用weak声明的实例变量指向nil,即实例变量的值为0。
  • copy:与strong类似,但区别在于实例变量是对传入对象的副本拥有所有权,而非对象本身。

1.2、RunTime

1、RunTime简称运行时,就是系统在运行的时候的一些机制,其中最主要的是消息机制。
2、对于C语言,函数的调用在编译的时候会决定调用哪个函数,编译完成之后直接顺序执行,无任何二义性。
3、OC的函数调用成为消息发送。属于动态调用过程。在编译的时候并不能决定真正调用哪个函数(事实证明,在编 译阶段,OC可以调用任何函数,即使这个函数并未实现,只要申明过就不会报错。而C语言在编译阶段就会报错)。
4、只有在真正运行的时候才会根据函数的名称找 到对应的函数来调用。

常用在我们代码中的具体情况

* 动态的添加对象的成员变量和方法
* 动态交换两个方法的实现
* 拦截并替换方法
* 在方法上增加额外功能
* 实现NSCoding的自动归档和解档
* 实现字典转模型的自动转换

这块可以延伸的太大了,可以参考
刨根问底Objective-C Runtime
南峰子的技术博客
Runtime简介及应用详解

1.3、RunLoop

RunLoop是什么呢?我们手机应用是事件驱动的整体架构,假如我们程序一直活着,如果没事就闲着,如果有什么事件把它唤醒,然后它就去分配执行事件,直到死了,才退出。 RunLoop是线程的基础架构部分,每一个 线程都有着对应的 run loop 对象。 它用来接受循环中的事件和安排线程工作,并在没有工作时,让线程进入睡眠状态。

RunLoop的作用

1、使程序一直运行并接受用户输入
2、决定程序在何时应该处理那些事件 (Event)
3、调用解耦 (Message Queue)---- 主调方 和 被调方,消息队列如何安排
4、节省CPU时间 ---- 没事的时候就闲着

RunLoop的 mode 类型

NSDefaultRunLoopMode :默认状态下,不滑动,空闲状态,程序启动之后就会被切到这个mode 
UITrackingRunLoopMode : 滑动的时候
UIInitializationRunLoopMode:私有的,可以追踪到的,这个app启动的时候是这个mode,第一个页面加载之后才回到第一个mode
NSRunLoopCommonModes:默认情况包括下第一个第二个,在这种情况下就是这两种情况都可以执行

详情可看
孙源@sunnyxx视频 RunLoop 介绍
YYKit 作者 深入理解RunLoop

1.4、NSThread、NSOperation、GCD

iOS有三种多线程编程的技术,这三种编程方式从上到下,抽象度层次是从低到高的,抽象度越高的使用越简单,也是Apple最推荐使用的。

  • NSThread :NSThread 轻量级最低,相对简单,但是需要手动管理所有的线程活动,如生命周期、线程同步、睡眠等
  • NSOperation : 自带线程周期管理,操作上可更注重自己逻辑,但是面向对象的抽象类,只能实现它或者使用它定义好的两个子类:NSInvocationOperationNSBlockOperation
  • GCD: 最高效,避开并发陷阱.

所以一般简单而安全的选择NSOperation实现多线程即可。而处理大量并发数据,又追求性能效率的选择GCD。

详情参考:谈iOS多线程(NSThread、NSOperation、GCD)编程
GCD你应该知道的事儿

1.5、Block、Delegate、Notification

  • Delegate:“一对一”,对同一个协议,一个对象只能设置一个代理delegate,所以单例对象就不能用代理。
  • Notification:“一对多”,在APP中,很多控制器都需要知道一个事件,应该用通知;但是通知需要及时删除。
  • Block:写法更简练,block注重结果的传输:比如对于一个事件,只想知道成功或者失败,并不需要知道进行了多少或者额外的一些信息。block需要注意防止循环引用。

推荐一篇写 block 不错的文章,Block的那些事

iOS 分享 -对象间的通信之delegate、notificationCenter与block

1.6、UDP、TCP、Socket、HTTP、POST、GET

TCP和UDP的区别

TCP与UDP的区别
  • TCP为传输控制层协议,为面向连接、可靠的、点到点的通信;
  • UDP为用户数据报协议,非连接的不可靠的点到多点的通信;
  • TCP侧重可靠传输,UDP侧重快速传输。
TCP连接的三次握手
* 第一次握手:客户端发送syn包(syn=j)到服务器,并进入SYN_SEND状态,等待服务器确认;
* 第二次握手:服务器收到syn包,必须确认客户的SYN(ack=j+1),同时自己也发送一个SYN包,即SYN+ACK包,此时服务器进入SYN+RECV状态;
* 第三次握手:客户端收到服务器的SYN+ACK包,向服务器发送确认包ACK(ack=k+1),此发送完毕,客户端和服务器进入ESTABLISHED状态,完成三次状态。

Scoket连接和HTTP连接的区别

  • HTTP协议是基于TCP连接的,是应用层协议,主要解决如何包装数据。Socket是对TCP/IP协议的封装,Socket本身并不是协议,而是一个调用接口(API),通过Socket,我们才能使用TCP/IP协议。
  • HTTP连接:短连接,客户端向服务器发送一次请求,服务器响应后连接断开,节省资源。服务器不能主动给客户端响应(除非采用HTTP长连接技术),iPhone主要使用类NSURLConnection。
  • Socket连接:长连接,客户端跟服务器端直接使用Socket进行连接,没有规定连接后断开,因此客户端和服务器段保持连接通道,双方可以主动发送数据,一般多用于游戏.Socket默认连接超时时间是30秒,默认大小是8K(理解为一个数据包大小)。

GET和POST的区别

  • HTTP: 超文本传输协议,是短连接,是客户端主动发送请求,服务器做出响应,服务器响应之后,链接断开。HTTP是一个属于应用层面向对象的协议,HTTP有两类报文:请求报文和响应报文。
    HTTP请求报文:一个HTTP请求报文由请求行、请求头部、空行和请求数据4部分组成。
    HTTP响应报文:由三部分组成:状态行、消息报头、响应正文。

  • GET:GET请求:参数在地址后拼接,没有请求数据,不安全(因为所有参数都拼接在地址后面),不适合传输大量数据(长度有限制,为1024个字节)。GET提交、请求的数据会附在URL之后,即把数据放置在HTTP协议头中。

  • POST: POST请求:参数在请求数据区放着,相对GET请求更安全,并且数据大小没有限制。把提交的数据放置在HTTP包的包体中。

* GET提交的数据会在地址栏显示出来,而POST提交,地址栏不会改变。
* GET请求能够被缓存, POST请求不能被缓存下来。
* GET请求会保存在浏览器的浏览记录中,POST请求不会保存在浏览器浏览记录中
* GET提交时,传输数据就会受到URL长度限制,POST由于不是通过URL传值,理论上书不受限。
* POST的安全性要比GET的安全性高;

HTTPS:安全超文本传输协议(Secure Hypertext Transfer Protocol),它是一个安全通信通道,基于HTTP开发,用于客户计算机和服务器之间交换信息,使用安全套结字层(SSI)进行信息交换,即HTTP的安全版。详情可看 阮一峰的网络日志

1.7、UITableView 的优化

UITableView是iOS开发中最常用也很实用并且最容易出现性能问题的的一个控件,本文列出了一些性能优化点,用于提高列表滚动的流畅性。

(1)复用
当TableView需要显示一个Cell时,会先从已创建的Cell中找一个可以重用的,然后展现到屏幕。一般情况下,可以被重用的Cell都滚到了屏幕区域外。如果慢慢地拖动TableView,就可以看到Cell不断地被重用(通过断点可以看到Cell的init或awakeFromNib没有被调用)。但是如果快速滚动,还是可能会看到Cell被创建。

  • 已经在StoryBoard的TableView中定义Cell的ProtoType则指定其ReuseIdentify,在delegate返回Cell的时候,则调用
[tableView dequeueReusableCellWithIdentifier:CellID];
  • Cell是从单独的xib加载
 [tableView registerNib:[UINib nibWithNibName:CellID bundle:nil] forCellReuseIdentifier:CellID];
  • Cell的ProtoType个数尽可能少,因为Cell的种类越多,TableView创建的Cell个数就越多,并且是成倍增长。

(2)缓存
缓存基本上可以解决大部分性能问题。TableView需要知道Cell的高度,才能对Cell进行布局;需要知道所有的Cell的高度,才能知道TableView本身的高度,所以,每次调用reloadData,都需要计算所有Cell的高度。我们要尽量减小高度计算的复杂度。

  • 缓存Cell的高度
1  高度固定、类型单一的Cell,在创建TableView的时候,直接设置其rowHeight属性。
2  对于高度固定、类型多样的Cell,实现代理方法,根据Cell的类型返回不同的高度:
3  对于高度不固定的Cell,由于需要动态计算高度,所以运算量必然会增大,但是还是存在优化的空间。常见的优化方式是,把cellHeight作为data的一个属性缓存起来,对于每一个data对应的每一个cell,就只需要计算一次高度。

当然,这样的方式,还是把运算量放到了TableView的代理方法内,其实也可以在创建ContentInfo本身的时候,就调用它的calcHeight方法,在代理方法里就可以可以直接返回info.cellHeight了。但也要结合实际情况进行取舍,因为有时候,有了数据源,但不一定需要展示TableView,提前计算高度反而会浪费时间。

另外在某种情况下也需要缓存Cell的资源,比如每一个Cell都需要用到的UIImage,UIFont,NSDateFormatter或者任何在绘制时需要的对象,推荐使用类层级的初始化方法中执行分配,并将其存储为静态变量。

(3)渲染

1  减少子View的个数和层级
子View的层级越深,渲染到屏幕上所需要的计算量就越大。
2 减少子View的透明图层
对于不透明的View,设置opaque为YES,这样在绘制该View时,就不需要考虑被View覆盖的其他内容。
3 避免CAlayer特效。
给Cell中View加阴影或圆角之类的会引起性能问题。

转自 http://blog.lessfun.com/blog/2015/04/01/uitableview-performence-improve/

1.8、SDWebImage的解读

注意调用类别的方法:

  • 从内存中(字典)找图片(当这个图片在本次程序加载过),找到直接使用;
  • 从沙盒中找,找到直接使用,缓存到内存。
  • 从网络上获取,使用,缓存到内存,缓存到沙盒。
SDWebImage图片加载过程

iOS图片加载框架-SDWebImage解读
AFNetworking 源码阅读

二、收录

2.1简述内存分区情况

* 代码区:存放函数二进制代码
* 数据区:系统运行时申请内存并初始化,系统退出时由系统释放,存放全局变量、静态变量、常量
* 堆区:通过malloc等函数或new等操作符动态申请得到,需程序员手动申请和释放
* 栈区:函数模块内申请,函数结束时由系统自动释放,存放局部变量、函数参数

ps: 栈和堆的不同

栈的空间由操作系统自动分配/释放,堆上的空间手动分配/释放。
栈空间是有限的,而堆是很大的自由存储区。

C中的malloc函数分配的内存空间是在堆上的,C++中对应的是new操作符。 
程序在编译期对变量和函数分配内存都在栈上进行,且程序运行过程中函数调用时参数的传递也在栈上。

2.2、区分下面指针的不同

  • const char *p;
  • char const *p;
  • char * const p;
  • const char * const p;
* const char *p定义了一个指向不可变的字符串的字符指针,可以这么看:const char *为类型,p是变量。
* char const *p与上一个是一样的。
* char * const p定义了一个指向字符串的指针,该指针值不可改变,即不可改变指向。这么看:char *是类型,const是修饰变量p,也就是说p是一个常量
* const char * const p定义了一个指向不可变的字符串的字符指针,且该指针也不可改变指向。这一个就很容易看出来了。两个const分别修饰,因此都是不可变的。
陆续收录中···

面试中当然还会出现其他各式各样的问题,以上是我整理的,如有错误,欢迎指出。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,185评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,445评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,684评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,564评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,681评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,874评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,025评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,761评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,217评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,545评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,694评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,351评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,988评论 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,778评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,007评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,427评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,580评论 2 349

推荐阅读更多精彩内容

  • *面试心声:其实这些题本人都没怎么背,但是在上海 两周半 面了大约10家 收到差不多3个offer,总结起来就是把...
    Dove_iOS阅读 27,134评论 30 470
  • OC的理解与特性 OC作为一门面向对象的语言,自然具有面向对象的语言特性:封装、继承、多态。它既具有静态语言的特性...
    克鲁德李阅读 447评论 0 0
  • OC的理解与特性OC作为一门面向对象的语言,自然具有面向对象的语言特性:封装、继承、多态。它既具有静态语言的特性(...
    LIANMING_LI阅读 512评论 0 0
  • 多线程、特别是NSOperation 和 GCD 的内部原理。运行时机制的原理和运用场景。SDWebImage的原...
    LZM轮回阅读 2,004评论 0 12
  • iOS面试小贴士 ———————————————回答好下面的足够了------------------------...
    不言不爱阅读 1,970评论 0 7