关于IOS的一些面试题

1、NSObject基类、元类、协议?

isa:是一个Class 类型的指针. 每个实例对象有个isa的指针,他指向对象的类,而Class里也有个isa的指针, 指向meteClass(元类)。元类保存了类方法的列表。当类方法被调 用时,先会从本身查找类方法的实现,如果没有,元类会向他父类查找该方法。同时注意的是:元类(meteClass)也是类,它也是对象。元类也有isa指针,它的isa指针最终指向的是一个根元类(root meteClass)。根元类的isa指针指向本身,这样形成了一个封闭的内循环。

 

2、单例原理?写一个最优单例。

static id _instance; 

+ (id)allocWithZone:(struct _NSZone *)zone 

{   

   static dispatch_once_t onceToken; 

   dispatch_once(&onceToken, ^{      

       _instance = [super allocWithZone:zone]; 

        });   

        return _instance; 

 

+ (instancetype)sharedData

 {  

      static dispatch_once_t onceToken;  

     dispatch_once(&onceToken, ^{     

          _instance = [[self alloc] init];   

     });   

     return _instance; 

 }  

 

-      (id)copyWithZone:(NSZone *)zone {   

       return _instance;

   }

 

    单利里面添加 NSMutableArray 的时候,防止多个地方对它同时便利和修改的话,需要加原子属性。并且用strong,,,并且写一个遍历和修改的方法。加上锁。  Lock  UnLock。

 

3、做什么性能优化?

1.  首页启动速度 

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

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

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

4.  尽量减小包的大小

5.  量化启动时间

6.  启动速度模块化 
v辅助工具(友盟,听云,Flurry)

2.  页面浏览速度 

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

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

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

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

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

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

3.  操作流畅度优化 

0.  tableview优化(cell的加载优化)

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

4.  数据库的优化 

0.  数据库设计上面的重构

1.  查询语句的优化

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

5.  服务器端和客户端的交互优化

0.  客户端尽量减少请求

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

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

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

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

6.  非技术性能优化 

0.  产品设计的逻辑性(产品的设计一定要符合逻辑,或者逻辑尽量简单)

1.  界面交互的规范(每个模块的界面的交互尽量统一,符合操作习惯)

2.  代码规范(这个可以隐形带来app性能的提高,比如用if else还是switch,或者是用!还是==)

3.  code review(坚持code Review持续重构代码,减少代码的逻辑复杂度)

4.  用ARC管理内存,尽量把views设置为透明,避免过于庞大的XIB,不要阻塞主线程,下载服务器图片尽量用剪切,压缩太耗费资源。

5.  使用重用和延迟加载。重视缓存的使用。使用使用Autorelease Pool。避免日期格式转换。

 

4、推送的原理。  

1). 应用在通知中心注册,由iOS系统向APNS请求返回设备令牌(device Token)      

2). 应用程序接收到设备令牌并发送给自己的后台服务器      

3). 服务器把要推送的内容和设备发送给APNS     

4). APNS根据设备令牌找到设备,再由iOS根据APPID把推送内容展示

   需要联网,用户的设备会于苹果APNS服务器形成一个长连接,用户设备会发 送uuid和Bundle idenidentifier给苹果服务器,苹果服务器会加密生成一个deviceToken给 用户设备,然后设备会将deviceToken发送给APP的服务器,服务器会将deviceToken存进 他们的数据库,这时候如果有人发送消息给我,服务器端就会去查询我的deviceToken,然 后将deviceToken和要发送的信息发送给苹果服务器,苹果服务器通过deviceToken找到 我的设备并将消息推送到我的设备上,这里还有个情况是如果APP在线,那么APP服务 器会于APP产生一个长连接,这时候APPF服务器会直接通过deviceToken将消息推送到设备上。

5、怎么高效加圆角?

使用layer.maskToBounds会强制Core Animation提前渲染屏幕的离屏绘制,性能会下降。

解决方案是:使用绘制技术。CGContextAddEllipseInRect添加圆,CGContextClip剪裁。或者使用贝塞尔曲线"切割"个这个图片, bezierPathWithRoundedRect

 

6、设计模式?

    1). MVC模式:Model View Control,把模型 视图 控制器 层进行解耦合编写。 

    2). MVVM模式:Model View ViewModel 把模型 视图 业务逻辑 层进行解耦和编写。 

    3). 单例模式:通过static关键词,声明全局变量。在整个进程运行期间只会被赋值一次。

    4). 观察者模式:KVO是典型的通知模式,观察某个属性的状态,状态发生变化时通知观察者。 

    5). 委托模式:代理+协议的组合。实现1对1的反向传值操作。

    6). 工厂模式:通过一个类方法,批量的根据已有模板生产对象。

 

7、程序运行后台的几种状态和顺序 

  1、各个程序运行状态时代理的回调:

  -(BOOL)application:(UIApplication *)application 

  willFinishLaunchingWithOptions:(NSDictionary *)launchOptions

  //告诉代理进程启动但还没进入状态保存


  - (BOOL)application:(UIApplication *)application 

 didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
   //告诉代理进程启动但还没进入状态保存


  - (void)applicationWillResignActive:(UIApplication *)application
   //当应用程序将要入非活动状态执行,在此期间,应用程序不接收消息或事件,比如来电话了


  - (void)applicationDidBecomeActive:(UIApplication *)application 
  // 当应用程序入活动状态执行,这个刚好跟上面那个方法相反


  - (void)applicationDidEnterBackground:(UIApplication *)application
  //当程序被推送到后台的时候调用。所以要设置后台继续运行,则在这个函数里面设置即可


  - (void)applicationWillEnterForeground:(UIApplication *)application
  当程序从后台将要重新回到前台时候调用,这个刚好跟上面的那个方法相反。


  - (void)applicationWillTerminate:(UIApplication *)application
  当程序将要退出是被调用,通常是用来保存数据和一些退出前的清理工作。这个需要要设置UIApplicationExitsOnSuspend的键值。


  - (void)applicationDidFinishLaunching:(UIApplication*)application
  当程序载入后执行

2、现在启动程序看看执行的顺序:

  启动程序
  lifeCycle[40428:11303] willFinishLaunchingWithOptions
  lifeCycle[40428:11303] didFinishLaunchingWithOptions
  lifeCycle[40428:11303] applicationDidBecomeActive

  按下home键

  lifeCycle[40428:11303] applicationWillResignActive
  lifeCycle[40428:11303] applicationDidEnterBackground

  双击home键,再打开程序

  lifeCycle[40428:11303] applicationWillEnterForeground
  lifeCycle[40428:11303] applicationDidBecomeActive

 

8、SDWebImage的缓存机制?

SDWebImage中为UIImageView 提供了一个分类UIImageView+WebCache.h,这个分类中有一个最常用的接口sd_setImageWithURL:placeholderImage:,会在真实图片出现前会先显示占位图片,当真实图片被加载出来后再替换占位图片。      加载图片的过程大致如下:    

1.首先会在SDWebImageCache 中寻找图片是否有对应的缓存, 它会以url 作为数据的索引先在内存中寻找是否有对应的缓存     

2.如果缓存未找到就会利用通过MD5处理过的key来继续在磁盘中查询对应的数据, 如果找到了, 就会把磁盘中的数据加载到内存中,并将图片显示出来    3.如果在内存和磁盘缓存中都没有找到,就会向远程服务器发送请求,开始下载图片  

4.下载后的图片会加入缓存中,并写入磁盘中

5.整个获取图片的过程都是在子线程中执行,获取到图片后回到主线程将图片显示出来       

SDWebImage原理:调用类别的方法:

1. 从内存(字典)中找图片(当这个图片在本次使用程序的过程中已经被加载过),找到直接使用。  

2. 从沙盒中找(当这个图片在之前使用程序的过程中被加载过),找到使用,缓存到内存中。  

3. 从网络上获取,使用,缓存到内存,缓存到沙盒。

 

    内存缓存是个通用话题,每个平台都会涉及到。cache算法会影响到整个app的表现。候选人最好能谈下自己都了解哪些cache策略及各自的特点。

    常见的有FIFO,LRU,LFU等等。由于NSCache的缓存策略不透明,一些app开发者会选择自己做一套cache机制,其实并不难。

    FIFO : 新访问的数据插入FIFO队列尾部,数据在FIFO队列中顺序移动;淘汰FIFO队列头部的数据;

LRU : 新数据插入到链表头部;每当缓存数据命中,则将数据移到链表头部;当链表满的时候,将链表尾部的数据丢弃;

LFU : 新加入数据插入到队列尾部(因为引用计数为1);队列中的数据被访问后,引用计数增加,队列重新排序;当需要淘汰数据时,将已经排序的列表最后的数据块删除;

 

9、  线上crash解决方案。

    线上crash的bug 首先还是先定位并分析如何解决。
    1、如果是服务端返回的异常数据没做兼容,就由服务端确保格式正确,客户端看情况是否要做兼容;
    2、如果是升级版本后的由于本地数据库或本地存储的数据格式未兼容等问题,一般需要撤下版本重新提交;
    3、如果是业务代码中只是简单的数组越界之类,也要重新发布版本,现在不能使用热更新。

常见的crash:

1、访问了一个已经被释放的对象。勾选Zombies检测。

    2、访问数组类对象越界或插入了空对象

    3、访问了不存在的方法。

    4、字节对齐。可能由于强制类型转换或者强制写内存等操作。 CPU 从32位变成64位,可能出现问题。

    5、堆栈溢出。大量创建,来不及释放会出来。

    6、多线程并发操作

    7、NSTimer。如果一个Timer 是不停repeat,那么释放之前就应该先invalidate。这时如果释放了timer,而timer其实还会回调,回调的时候找不到对象就会挂掉

 

10、自动释放池如何实现?

    当您向一个对象发送一个autorelease消息时,Cocoa就会将该对象的一个引用放入到最新的自动释放池。它仍然是个正当的对象,因此自动释放池定义的作用域内的其它对象可以向它发送消息。当程序执行到作用域结束的位置时,自动释放池就会被释放,池中的所有对象也就被释放。

    ojc-c 是通过一种"referring counting"(引用计数)的方式来管理内存的, 对象在开始分配内存(alloc)的时候引用计数为一,以后每当碰到有copy,retain的时候引用计数都会加一, 每当碰到release和autorelease的时候引用计数就会减一,如果此对象的计数变为了0, 就会被系统销毁.

 

11、ipa体积如何压缩

    1、配置编译选项 (Levels选项内)Genetate Debug Symbols  设置为NO,这个配置选项应该会让你减去小半的体积。

    2、舍弃架构armv7,因为armv7用于支持4s和3gs,4s是2011年11月正式上线,虽然还有小部分人在使用,但是追求包体大小的完全可以舍弃了。

    3、编译的版本必须是发布版本,

    4、查找内部使用到的第三方库,一方面可以进行删减代码,用不到的类,直接删除,还有第三方库中的图片资源统统删除掉,如果能够自己手写实现的,那费功夫自己写吧

    其他的资源相关:

图片:

压缩图片不重要的图片可适当采用8bit PNG图片

    1.什么是矢量图 矢量图是由计算机的算法产生的,可以无限放大或缩小,不会有任何损失,通常由矢量软件制作。

    2.什么是位图 位图是由一个一个的小色块组成,放大后会看到那些小色块,同一面积内小色块越多,分辨率就越高。

    3.矢量图的优缺点 可以无限放大或缩小,不会影响图像素质,文件体积较小,编辑灵活。缺点是表达的色彩层次不清,整体观感效果不如位图

    4.位图的优缺点 不能放太大,减少文件分辨率后会影响图片质量,图片战胜空间较大,优点是能很细腻地表达图片的效果,图片表达效果非常好

    5.什么情况下用位图,什么情况下用矢量图 一些对图片要求高的用位图,例如照片。其他的尽量用矢量图。例如文字、表格、卡通图片等

    去掉无用的图片

    用代码绘制简单的纯色图片 用Sketch和PaintCode快速得到绘制代码

如果不需要使用透明,可以用jpeg代替PNG。jpeg减少了些效率但更加小。需权衡性能,大小。

    对32位的图片,尽肯能的使用高压缩率,使用PS的“Save For Web”功能,可以有效的减小JPEG和PNG图片的尺寸。 默认情况下,在build时,PNG图像就被pngcrush压缩。

    音频

    压缩音频,尽可能使用AAC或者MP3格式,并且使用一个较低的码率。通常44.1khz的码率有点浪费,降低一定的码率也不会丢失多少音质

    视频

    视频也可以使用类似于音频的处理方法,音视频的压缩可以很大程度的压缩,但是要注意压缩的格式,是不是会增加编解码的负担,这要权衡考虑。

    Assets

    检查bundle中的无用文件,不要打包到app或者静态库中。可以点击文件,在右侧的file inspector里面的target membership中取消勾选;或者在build phase里面的Copy Bundle Resources中去掉。

    确定dead code(代码被定义但从未被调用)被剥离,build setting 里DEAD_CODE_STRIPPING = YES。 去掉冗余的代码,即使一点冗余代码,编译后体积也是很可观的。

 

12、MVC、MVVM、MVP

    MVC有两个很明显的问题:1.m层和v层直接打交道,导致这两层耦合度高

2.因为所有逻辑都写在c层,导致c层特别臃肿。因此出现MVP和MVVM。MVP:p层代替了了c层,v层和m层的交互被p层隔断,从理论上去除了v和m层的耦合。但是造成p层比原来的c层更加臃肿,为了缓解这种臃肿,MVVM出现了

,简单的来说MVVM其实就是MVP中把P层削弱为VM层,部分简单的逻辑职责分给了View层。这样做使得VM层相比起P层就没有这么臃肿了

    MVC

    Model代表了描述业务路逻辑,业务模型、数据操作、数据模型的一系列类的集合。这层也定义了数据修改和操作的业务规则。

    View代表了UI组件,像CSSJQueryhtml等。他只负责展示从controller接收到的数据。也就是把model转化成UI

    Controll负责处理流入的请求。它通过View来接受用户的输入,之后利用Model来处理用户的数据,最后把结果返回给ViewControll就是ViewModel之间的一个协调者。

    MVP:

    Model层代表了描述业务逻辑和数据的一系列类的集合。它也定义了数据修改和操作的业务规则。

    View代表了UI组件,像CSSJQueryhtml等。他只负责展示从Presenter接收到的数据。也就是把模型(译者注:非Modle层模型)转化成UI

    Presenter负责处理View背后所有的UI事件。它通过View接收用户输入,之后利用Model来处理用户的数据,最后把结果返回给View。与ViewController不同,ViewPresenter之间是完全解耦的,他们通过接口来交互。另外,presenter不像controller处理进入的请求。

    MVP模式关键点:

    01.用户和View交互。

    02.ViewPresenter是一对一关系。意味着一个Presenter只映射一个View

    03.View持有Presenter的引用(译者注:应该是通过接口交互,并不直接引用Presenter),但是View不持有Model的引用(译者注:即使接口,也不会)。

    04.ViewPresenter之间可以双向交互。

MVVM:

Model层代表了描述业务逻辑和数据的一系列类的集合。它也定义了数据修改和操作的业务规则。

    View代表了UI组件,像CSSJQueryhtml等。他只负责展示从Presenter接收到的数据。也就是把模型转化成UI

    View Model负责暴漏方法,命令,其他属性来操作VIew的状态,组装model作为View动作的结果,并且触发view自己的事件。

    MVVM模式关键点:

    01.用户和View交互。

    02.ViewViewModel是多对一关系。意味着一个ViewModel只映射多个View

    03.View持有ViewModel的引用,但是ViewModel没有任何View的信息。

    04.View ViewModel之间有双向数据绑定关系。

 

13、main()之前的过程有哪些?

    1)dyld 开始将程序二进制文件初始化

    2)交由ImageLoader 读取image,其中包含了我们的类,方法等各种符号(Class、Protocol 、Selector、IMP)

    3)由于runtime 向dyld 绑定了回调,当image加载到内存后,dyld会通知runtime进行处理

    4)runtime 接手后调用map_images做解析和处理

    5)接下来load_images 中调用call_load_methods方法,遍历所有加载进来的Class,按继承层次依次调用Class的+load和其他Category的+load方法

    6)至此 所有的信息都被加载到内存中

    7)最后dyld调用真正的main函数

注意:dyld会缓存上一次把信息加载内存的缓存,所以第二次比第一次启动快一点   

 

14、事件响应链。

   从程序启动开始到view显示顺序:

    1、start。(先加载framework,动态静态链接库,启动图片,info.plish,pch预处理等)

    2、main函数。

    3、UIApplication函数。(初始化UIApplication单例对象,初始化UIApplication对象的代理APPDelegate对象)

    4、检查Info.plist设置的Xib文件是否有效,

    5、创建显示的Key window,rootViewController与关联的View。

    6、建立一个主事件循环,包含UIApplication的RunLoop来开始处理事件。

    UIApplication:

    通过window管理视图;发送Runloop封装好的control消息给target;处理URL,应用图标警告,联网状态,状态栏,远程事件等。

    AppDelegate:

管理UIApplication生命周期和应用的五种状态

(notRunning/inactive/active/background/suspend)。

    Key Window:

    显示view;管理rootViewcontroller生命周期;发送UIApplication传来的事件消息给view。

    rootViewController:

    管理view(view生命周期;view的数据源/代理;view与superView之间事件响应nextResponder的“备胎”);界面跳转与传值;状态栏,屏幕旋转。

    view:

通过作为CALayer的代理,管理layer的渲染(顺序大概是先更新约束,再layout再display)和动画(默认layer的属性可动画,view默认禁止,在UIView的block分类方法里才打开动画)。layer是RGBA纹理,通过和mask位图(含alpha属性)关联将合成后的layer纹理填充在像素点内,GPU每1/60秒将计算出的纹理display在像素点中。布局子控件(屏幕旋转或者子视图布局变动时,view会重新布局)。事件响应:event和guesture。

 

15、ViewController的执行顺序?

按照执行顺序排列: 

1. initWithCoder:通过nib文件初始化时触发。

2. awakeFromNib:nib文件被加载的时候,会发生一个awakeFromNib的消息到nib文件中的每个对象。       

3. loadView:开始加载视图控制器自带的view。

4. viewDidLoad:视图控制器的view被加载完成。  

5. viewWillAppear:视图控制器的view将要显示在window上。

6. updateViewConstraints:视图控制器的view开始更新AutoLayout约束。 

7. viewWillLayoutSubviews:视图控制器的view将要更新内容视图的位置。  

8. viewDidLayoutSubviews:视图控制器的view已经更新视图的位置。 

9. viewDidAppear:视图控制器的view已经展示到window上。  

10. viewWillDisappear:视图控制器的view将要从window上消失。 

11. viewDidDisappear:视图控制器的view已经从window上消失。

 

16、性能分析的工具。

   1、 静态分析analyze。静态Analyze 工具,以及运行时Profile 工具,通过Xcode工具栏中Product->Profile可以启动,检测不合理的创建。

2、instruments工具:

  1). Time Profiler: 性能分析

  2). Zombies:检查是否访问了僵尸对象,但是这个工具只能从上往下检查,不智能。

  3). Allocations:用来检查内存,写算法的那批人也用这个来检查。

  4). Leaks:检查内存,看是否有内存泄露。

 

17、AFNetWorking底层实现原理。

AFNetworking主要是对NSURLSession和NSURLConnection(iOS9.0废弃)的封装,其中主要有以下类: 

1). AFHTTPRequestOperationManager:内部封装的是NSURLConnection, 负责发送网络请求, 使用最多的一个类。(3.0废弃) 

2). AFHTTPSessionManager:内部封装是NSURLSession, 负责发送网络请求,使用最多的一个类。 

3). AFNetworkReachabilityManager:实时监测网络状态的工具类。当前的网络环境发生改变之后,这个工具类就可以检测到。

4). AFSecurityPolicy:网络安全的工具类, 主要是针对HTTPS 服务。 

5). AFURLRequestSerialization:序列化工具类,基类。上传的数据转换成JSON格式    (AFJSONRequestSerializer).使用不多。

6). AFURLResponseSerialization:反序列化工具类;基类.使用比较多: 

7). AFJSONResponseSerializer; JSON解析器,默认的解析器. 

8). AFHTTPResponseSerializer; 万能解析器; JSON和XML之外的数据类型,直接返回二进 制数据.对服务器返回的数据不做任何处理. 

9). AFXMLParserResponseSerializer; XML解析器;

猜你喜欢

转载自blog.csdn.net/PDD_1128/article/details/80730088