求职笔记-iOS篇

前言

今年年初求职时,整理、回顾了学习iOS开发以来收获的知识,此篇为当时的笔记。

插一段我对面试的看法。
公司要在短短的几个小时内要详细了解求职者,并且求职者可能远远大于岗位需求,这个并不是一件简单的事情。
求职分为几大部分:
1、简历筛选,去掉大部分不符合要求的;
2、笔试,去掉没有准备的;
3、初面,去掉基础不扎实的;
4、复试,去掉综合能力欠缺的;
5、HR面,去掉三观不正确的;
在这个过程中,一个好的求职者会不断修改简历,已适应不同公司的要求;提前整理、回顾基础知识,以应对笔试和初试;对过去的工作经历进行总结,不断提高自己的综合能力;并在生活与工作中,培养好的工作习惯和态度
在这个过程中,笔记就显得很重要。

面试题

这是面试的常问问题,仅供大家参考;
如果觉得有用,不妨点个喜欢

1、strong、weak、unsafe_unretained 这三个修饰符分别是什么?
2、performSelector为什么会内存泄漏?
3、如何对真机的crash日志进行分析?
4、对RunLoop的理解?
5、对象回收时Weak指针自动被置为nil的实现原理?
6、常见的持久化实现方法?
7、动画中的图层树、逻辑树、动画树、显示树分别是什么?
8、APP的生命周期(应用程序的状态)有哪些?
9、多线程中同步方式有哪些?
10、一个十级台阶,你在第一级台阶,每次能往上走一级或者两级台阶,问走到第十级台阶有多少种方案?

正文

以下是iOS相关的知识点。

异常和捕获

1、try-catch

@try{
//raise exception
}
@catch (NSException *exception) {
// cannot raise exception
}
@finally {
// execute
}
// execute

2、捕获
NSSetUncaughtExceptionHandler

3、线上崩溃分析
在上面的捕获函数中,捕捉堆栈。
[NSThread callStackSymbols]

4、线上卡顿统计
CADisplayLink每帧回调,用时间间隔算帧率;
计算每次runloop的耗时。

UIWindow

UIWindow继承自UIView,是视图的容器。
一般的app只需一个UIWindow,在AppDelegate中。
UIWindow的主要作用:

  • 作为最顶层的视图容器,存放app的视图;
  • 传递触摸和键盘等事件;

KVO与Notification的异同

KVO和Notification本质都是观察者模式。
KVO是被观察者直接发消息(-willChange-didChange),耦合性较强,适合某些绑定,比如说界面上的进度条显示;
Notification是被观察者发消息给NotificationCenter,再由NotificationCenter转发出去,耦合性较低,适合登录、等级变化、监听全局的某个属性变化;

Objective-C消息机制的原理

先介绍Objective-C的类结构:

@interface NSObject <NSObject> {
    Class isa  OBJC_ISA_AVAILABILITY;
}
typedef struct objc_class *Class;

每一个OC对象本质上都是一个结构体,包括成员变量列表和成员方法列表,对象通过isa指针指向类;
类本质上也是一个对象,是元类(meteClass)的实例,元类包括类方法的列表,类通过类的isa指针指向元类;
所有的元类继承根元类,根元类isa指针指向本身;

objc_msgSend方法:objc_msgSend含两个必要参数:receiver、方法名(selector)
[receiver message];将被转换为:objc_msgSend(receiver, selector);
带参数的情况是:objc_msgSend(receiver, selector, arg1, arg2, …);

当向一个对象发送消息时,objc_msgSend方法根据对象的isa指针找到对象的原来类,然后在类的方法列表中查找selector;
如果查找不到,通过Class super_class指针找到父类,并在父类的方法列表查找,直到NSObject类;
查找到selector,objc_msgSend方法根据方法列表的内存地址调用该实现;
每个类都有一个独立的缓存struct objc_cache *cache,缓存方法调用的结果。

对象回收时Weak指针自动被置为nil的实现原理

Runtime维护着一个Weak表,用于存储指向某个对象的所有Weak指针;
Weak表是Hash表,Key是所指对象的地址,Value是Weak指针地址的数组;
在对象被回收的时候,经过层层调用,会最终触发下面的方法将所有Weak指针的值设为nil。

runtime源码,objc-weak.m 的 arr_clear_deallocating 函数。
Weak指针如何注册到Weak表中、如何维护hash表可以参考objc-weak.m中的其它源码。

从实现中可以看出,Weak指针的使用涉及到Hash表的增删改查,有一定的性能开销。
Weak指针的实际应用:

iOS 8 特有iOS相关的漏洞
- (void)dealloc {
    [[NSNotificationCenter defaultCenter] removeObserver:self];
}

iOS 8 的UIScrollView的delegate属性

持久化实现

ios中存储数据基本上就是plist、sqlite和CoreData (NSUserDefault其实也是plist)
常见的持久化实现:
1、实现NSCoding,配合runtime读取属性,再用NSKeyedArchiver存储到文件中;
2、实现NSCoding,存储到NSUserDefault;
3、数据库,使用SQLitePersistentObjects写入db;
4、使用CoreData;

动画性能优化

动画的视图结构

视图树/图层树:UIView,每个view对应一个calayer,管理触摸、手势等交互事件;
模型树/逻辑树(目标帧) :CALayer - modelLayer(),不涉及响应链(通过视图层级关系传递触摸事件的机制)
**呈现树/动画树(当前帧) **:presentationLayer(), 动画过程中的当前值
渲染树/显示树(下一帧) :图层和动画打包提交到渲染服务后反序列化所得树,被用于生成gl三角形

常见的动画方式:

  • UIView blockAnimation
  • CAAnimation

动画耗时在于:
图片加载、alpha透明、动画代码混乱、离屏渲染、帧动画过多、布局计算、遮罩、图片过大;

某些问题不可避免,比如说图片加载、帧动画等,以下是自己总结的一些经验:

  • CADisplayLink控制帧动画的帧率,避免动画的绘制速率超过帧率

🤔想想为什么?

  • 避免使用alpha透明的图片

  • 使用GCD和CAAnimation来管理动画的流程;

使用NSOperationQueue或许也是解决方案。

  • 减少遮罩以避免离屏渲染,避免光栅化视图的频繁更新;
  • 使用代码布局,避免autolayout;

聊天室中UITableView的优化

聊天室中,消息的显示使用的是UITableView;
每一条消息是单独的UITableViewCell,通过富文本显示聊天消息,耗时操作是:富文本拼接、高度计算、滚动显示;

优化两个方面:
业务方向:

  • 下发房间配置文件,房间分普通、热闹、火爆等状态,某些情况下省略不必要的消息,再进行发言等级控制等;
  • 消息合并,对同类型的消息进行合并;

代码方向:

  • 富文本根据消息内容进行拼接后缓存;
  • 高度在计算过一次之后,同样缓存;(boundingRectWithSize 可以提前计算出高度)
  • 根据帧率动态加载消息数量,当进行消息追赶的时候,多条消息调用一次insert,用CADisplayLink保证添加速率和帧率一致;
    代码创建cell
  • 图像预加载,程序在启动的时候会进行礼物版本同步,把礼物图片预先下载好,在显示直接通过富文本进行图片拼接;(为了避免锯齿,图像大小和显示使用整数)

TCP/IP

3次握手-建立连接
1、A发送sync报文;seq=x Sync=1
2、B回复ack报文;seq=y Sync=1 ack=x+1
3、A回复ack报文;seq=x+1 Sync=1 ack=y+1

4次握手-断开连接
1、A端发送FIN,停止发送报文;A进入FIN-WAIT
2、B端发送ACK,表示收到,继续发送报文; A收到报文进入FIN2-WAIT
3、B端发送FIN,停止发送报文;B进入CLOSE_WAIT
4、A端收到FIN,发送ACK报文,A进入TIME_WAIT状态

TIME_WAIT经过两个最大报文段生存时间后,进入CLOSE状态。(如果A在time_wait过程中,收到FIN报文,表示发送的ACK丢包了,重新发)

如何下载一个超大的文件?支持断点续下、暂停、取消的功能。

1、NSURLConnection / NSURLSessionTask 实现下载,通过Range字段实现断点续传;

存在的内存占用过多的问题。
解决方案:新建文件,然后用NSOutputStream把下载的数据流直接append到文件中。

2、更简单的解决方案:NSURLSessionDownloadTask。

缺点:下载完成之后才能获得完整的文件,如果在下载过程中直接关闭退出程序,会丢失数据,因为数据保存在内存;

断点续传

http实现断点续传的关键地方就是在httprequest中加入“Range”头。
Range头域可以请求实体的一个或者多个子范围。例如,

表示头500个字节:bytes=0-499
表示第二个500字节:bytes=500-999
表示最后500个字节:bytes=-500
表示500字节以后的范围:bytes=500-

利用NSOutputStream写文件,在任务完成的代理方法里面,NSOutputStream关闭并且清空,对应的task清空,对应的session清空;
在 NSURLRequest中有一个HTTPBodyStream,可以方便的接受服务器返回的流数据。

HTTP协议

http(超文本传输协议)是一个基于请求与响应模式的、无状态的、应用层的协议,常基于TCP的连接方式
http请求由三部分组成,分别是:请求行、消息报头、请求正文。
常见状态码:
200 成功
400 请求的语法错误
403 Forbidden
404 not found 服务器找不到请求的资源
408 Request Time out
500 服务器内部错误

请求头
GET 请求方法、地址、协议版本
GET /foo.php?first_name=John&last_name=Doe&action=Submit HTTP/1.1

请求体(POST请求有)
form-data

NSURLRequest 的allHTTPHeaderFields 可以看到以下属性

Cache-Control →no-store, no-cache, must-revalidate, post-check=0, pre-check=0
Connection →keep-alive
Content-Encoding →gzip
Content-Type →text/html; charset=utf-8
Date →Fri, 10 Mar 2017 13:35:42 GMT
Expires →Thu, 19 Nov 1981 08:52:00 GMT
Pragma →no-cache
Server →nginx
Transfer-Encoding →chunked
X-Powered-By →PHP/5.4.16

HTTP响应也是由三个部分组成,分别是:状态行、消息报头、响应正文

HTTP/1.1 200 OK // 包含了HTTP协议版本、状态码、状态英文名称
Server: Apache-Coyote/1.1 // 服务器的类型
Content-Type: image/jpeg // 返回数据的类型
Content-Length: 56811 // 返回数据的长度
Date: Mon, 23 Jun 2014 12:54:52 GMT // 响应的时间

NSHTTPURLResponse的allHTTPHeaderFields 可以看到以上属性

iOS目录结构


Documents 是常用文档目录,会和iTunes同步;
Library 是资源库文件,里面有Caches和Preference两大目录;
Caches一般存放缓存文件,较大;
Preference存放个人设置文件,iTunes会同步;
tmp 目录是临时文件,应用关闭后,可能会被删除。

说道文件夹,就离不开序列化。
NSKeyedArchiver
实现NSCoding协议即可实现序列化;
配合运行时机制,可以动态实现将类的所有属性序列化。
相对应的,可以用 NSKeyedUnarchiver 实现反序列化。

APP的生命周期

应用程序的状态

  • Not running未运行:程序没启动;
  • Inactive未激活:程序在前台运行,未接收到事件;
  • Active激活:程序在前台运行,接受到事件;
  • Backgroud后台:程序在后台运行,在后台停留一段时间后进入挂起状态(Suspended),如果有音乐、下载等特殊任务的程序可以长期处于Backgroud状态;
  • Suspended挂起:程序在后台且不运行,当收到系统内存不足的warning时被清除出内存;


问题1:UIAlertView弹出的时候,APP处于哪一个状态?
低电量提出弹出的时候,APP又处于哪一个状态?

Inactive和Background。

在加载到前台过程中,经历了Launch和Running两大状态;
start->main() -> UIApplicationMain() -> Load UI file -> willFinishLaunchingWithOptions: -> Restore UI state -> didFinish
Active App => Application Become Active
接着就是不断进行RunLoop。
还有一种:加载应用程序到后台(在后台打开网易云音乐)
前面的start部分一致,但最终进入的不是Foreground状态,而是Background状态;
在Background长时间不运行,会导致应用程序进入Suspended状态;

线程安全问题

线程之间的资源共享,本质是对同一对象、变量、文件等进行修改和访问,主要有以下同步方式:

  • 加锁;
  • 原子操作;
  • sync代码块;
@synchronized( 同一对象){
  线程执行代码;
  }

NSOperationQueue 可以停止队列还没执行
suspended
但是不能终止当前操作。

RunLoop

此段,部分摘自文章

简单运行执行runlooprun函数并不会让系统停住等待事件,而是需要在运行runloop之前添加source,只有在有source的情况下线程才会停下来监听各种事件。ios整个系统基本上是基于runloop这种架构的,ios程序的main线程整体上也是基于runloop的,各种事件的响应应该也是基于source这种思路。
UIApplicationMain() 函数,这个方法会为main thread 设置一个NSRunLoop 对象;
Run loop同时也负责autorelease pool的创建和释放;
Run loop接收输入事件来自两种不同的来源:输入源(input source)和定时源(timer source);
典型的子线程异步请求,需要开启runLoop:AF 的 self.inputStream;
当在其他线程上面执行selector时,目标线程须有一个活动的run loop。对于你创建的线程,这意味着线程在你显式的启动run loop之前是不会执行selector方法的,而是一直处于休眠状态;
苹果不允许直接创建 RunLoop,它只提供了两个自动获取的函数:CFRunLoopGetMain() 和 CFRunLoopGetCurrent()。
一个 RunLoop 包含若干个 Mode,每个 Mode 又包含若干个 Source/Timer/Observer。

RunLoop 和 帧率之间的关系
用户操作设备,相关的操作事件被系统生成并通过UIKit的指定端口分发。事件在 内部排成队列,一个个的分发到Main run loop 去做处理。UIApplication对象是第一个接收到时间的对象,它决定事件如何被处理。触摸事件分发到主窗口,窗口再分发到对应出发触摸事件的 View。其他的事件通过其他途径分发给其他对象变量做处理。
大部分的事件可以在你的应用里分发,类似于触摸事件,远程操控事件(线控耳机等) 都是由app的 responder objects 对象处理的。Responder objects 在你的app里到处都是,比如:UIApplication 对象,view对象,view controller 对象,都是resopnder objects。大部分事件的目标都指定了resopnder object,不过事件也可以传递给其他对象。比如,如果view对象不处理事件,可以传给父类view或者view controller。

一个 RunLoop 包含若干个 Mode,每个 Mode 又包含若干个 Source/Timer/Observer。每次调用 RunLoop 的主函数时,只能指定其中一个 Mode,这个Mode被称作 CurrentMode。如果需要切换 Mode,只能退出 Loop,再重新指定一个 Mode 进入。这样做主要是为了分隔开不同组的 Source/Timer/Observer,让其互不影响。

main():
    file_fd = open ("logfile")
    x_fd = open_display ()
    construct_interface ()
    while changed_fds = select ({file_fd, x_fd}):
        if file_fd in changed_fds:
            data = read_from (file_fd)
            append_to_display (data)
            send_repaint_message ()
        if x_fd in changed_fds:
            process_x_messages ()

CFRunLoop源码

如何计算帧的持续时间:
用CACurrentMediaTime()记录当前时间,然后和上一帧记录的时间去比较。得到真实的每帧持续的时间,然后代替硬编码的六十分之一秒,来更新UI。

总结

此篇的iOS知识点并不全面,仅仅是求职的一些笔记,后续接着写工作遇到的iOS相关问题,欢迎关注iOS开发随笔

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

推荐阅读更多精彩内容

  • 1,NSObject中description属性的意义,它可以重写吗?答案:每当 NSLog(@"")函数中出现 ...
    eightzg阅读 4,131评论 2 19
  • 1.属性readwrite,readonly,assign,retain,copy,nonatomic 各是什么作...
    曾令伟阅读 1,042评论 0 10
  • 喜欢与不喜欢之间只多了一个“不”字,却隐藏了许许多多的秘密。人,无论在何时何地都会有不同的情绪,无需一探究竟。你说呢?
    庄田木阅读 135评论 0 0
  • 主要内容:坚持手帐100天给我带来什么改变关于坚持10000小时 最近做了什么。 很多时候我们觉得自己很忙,但是绝...
    霖霖的手帐阅读 940评论 2 3
  • 独处能保持自己做好 要求周围一切环境都符合心意 其实是对自己的一种苛责
    MaryCeeport阅读 241评论 0 0