iOS常见面试题,留个印,不定时更新,以作后用...QAQ

 

1.适配问题程序员

双关问句:你说下关于iOS的适配怎么处理的?编程

  iOS适配是有两个的,一是版本适配,即APP要运行在不一样版本的iOS系统下;其二是屏幕适配,即不一样的设备上要如何处理保证不一样大小的屏幕上显示的正确;windows

版本适配api

  通常作版本是适配是当前最高版本向下兼容两个版本,若是你是微信这类用户量巨大的app那么基本的全部使用版本都要作适配;方法为base SDK是目前的最高版本,而后development target设置为想要兼容到的最低版本便可;数组

屏幕适配安全

  屏幕适配经历过几个时期服务器

  ①frame适配:须要多套的代码实现,较为麻烦;微信

  ②autoResizing适配:只能作父子控件的适配,不可以同级控件作适配;iOS5以前使用;网络

  ③autoLayout适配:既能够用来设置父子控件的关系,也能实现同级控件的适配;多线程

    两个重要的概念:”参照”和”约束”;

    一句经典标准:”全部的约束都是数学的线性关系”;

    在sb中使用autolayout较为简单,纯代码方式较为复杂,为了解决该问题,第三方”masonry”应运而生;

    autoLayout推出于iOS6,大热于iOS7,技术的适应期.......

  ④sizeclass,sizeclass是基于autolayout的分屏处理,这点很重要!

 

  注意点:

    autoresizing和autoLayout不可以同时使用;

    不集成第三方使用autoLayout纯代码的方式须要屏蔽掉autoresizing;

 

2.网络问题

  网络类的问题相对于其余有点多元化,即什么方面都有可能涉及到,好比协议类问题,链接类问题等;这里只作部分说明;

  2.1)协议类问题

    简单说下你所了解的TCP,UDP,HTTP协议.

    凡是涉及协议类的东西,通常和如今流行的直播类相关,如何公司有意朝这个方向或者原本就是这个方面的,这个是必问的题目;

    首先不要局限于给出的题目,还能够拓展一下,好比XMPP等这些都会为你加分;

    TCP:传输控制协议;官方介绍Google你懂得;

      通俗的解释就是:用户从网络获取数据时候须要知足必定的条件,tcp协议就是个条件;

      知足条件能作什么?若是不知足呢?

      实现TCP协议,既是”三次握手协议”,该条件保证了数据的安全性;

    UDP:用户数据报协议;

      是一个简单的数据报的运输层协议;顾名思义,就是作数据传递用的;区别于TCP,他就是不知足那个条件的,即我只要遵循UDP便可,不须要再链接前握手确认,由于省了不少步骤,因此速度较快,但没有回执安全性没有保障;

    HTTP:超文本传输协议;

      该协议是一个”应用层”的协议;

      可能不少人有过这样的遭遇.....

      遭遇一:http协议和TCP/IP协议有什么区别?

      遭遇二:http协议和socket有什么关系?

      遭遇三:tcp/ip和socket有什么联系?

        诸如此类的问题,还能举出来一堆,并且你都不想面对......究其缘由实际上是对网络的基本架构不是那么的清楚,全部咱们从基本的开始提及;

      —->以上网看电影为例子

      物理层

        该层做用是链接两个或多个计算机,传递”0”和”1”的电信号;表明:光纤,同轴电缆;

      数据链路层

        处理电信号转化为网络二进制码再进行传输;表明:网桥,交换机,中继器等;

      网络层

        寻址,创建链接;即给你的电脑与资源电脑创建联系关系;(IP->IP),表明:路由器;

      传输层

        网络层接受和发送了信息,但处理不了,不知道传递给哪一个应用程序,好比你获取到了电影,可是不知道该怎么才能打开,传输层经过网卡给应用程序编号,经过传递过来信息里面附带的编号,把信息给到指定的应用程序;创建了端口(应用程序(电影播放器))与端口的通讯;表明:PC,手机;

        该层协议:

        ->TCP协议:安全链接协议/三次握手协议:可以保障信息的安全性。

        ->UDP协议:报文头协议,不关心是否接受到信息,效率高,但不安全;

      会话层

        创建了一套自动接收和发送信息,自动网络寻址的机制。

      表示层

        解决不一样系统之间的语法问题(翻译官),好比Linux下的QQ和windows下的QQ通讯问题;

      应用层

        规定应用程序的数据传输格式。

          http协议:超文本传输协议

          file协议:文件传输协议

          mail协议:邮件协议

 

       如今上面的问题基本明白的差很少了吧,http协议是一个应用层的协议,主要作的是包装数据的任务,tcp/ip是传输层的协议,主要负责接收和发送数据的任务;socket是对tcp/ip协议的封装和应用,这个主要是给程序员用的,用来更加容易的处理tcp/ip栈而已;

 

  2.2)多线程问题

    ①概念问题

      说说你对线程和进程的理解?

        进程是程序运行中,是分配和管理资源的基本单位,

        线程能够看做为进程中的一部分,能够理解为一个轻量级的进程;

          多线程的优缺点(空间和时间的转换)

           >优势:

          1)能够适当的提升程序到执行效率

          2)能够适当的提升资源到利用率(cpu和内存的利用率)

          3)子线程自动销毁

           >缺点:

          1)开启线程会占用内存空间,若是开启线程过多会占用过多的内存,下降程序性能

          2)线程过多,cpu的消耗越大。

          3)线程越多,程序的设计就越复杂,线程之间通讯和资源数据传递共享越难。

 

    ②具体操做问题

      你是具体怎么对线程处理的?

        比较面向对象的处理方法能够用NSOperation;(是OC基于GCD的封装);

        效率高一点的可使用GCD; 

          GCD—>

            1>建立队列

              串行,并行(并发),主队列,全局

              dispatch_queue_t (队列类型)

              串并行是creat获得,主队列和全局队列是get获得

            2>建立任务

              经过block来建立

            3>把任务添加到队列(指定执行任务函数)

              异步dispatch_async(); 

              同步dispatch_sync();

 

         注意问题:gcd容易涉及到单例,单例的建立分为好几种,线程不安全的,线程安全的,须要等待的,一次执行的;通常的建立方式,是”一次执行”的方式;

         方法:static修饰单例对象—>经过dispatch_once_t 判断;

        NSOperation—>

             a.  NS0peration是一个抽象类(没有实现方法,用来管理子类)。

             b.  NSOperation的两个子类:

             >NSInvovcationOperation 

            建立对象,调用star执行操做,star并不会开辟新线程,只有放在NSOperationQueue队列中,才会执行异步操做。

            >NSBlockOperation

             建立对象,经过addExecutionBlock添加操做。只要NSBlockOperation封装操做数 > 1 就会执行异步操做。

         NSOperationQueue->

          >建立对象

          >调用start方法执行操做

           注意:调用start并不会开辟新线程,而是在当前线程下同步执行,只有将NSOperation放到队列NSOperationQueue中才会执行异步操做。

 

    ③用法问题

      —>什么地方会使用多线程?

      耗时操做,可使用;但若是多线程使用过多也很差;(详见时间和空间的解释);

 

3.第三方问题

  AFN的原理,SDWebImgae的原理,你使用其余第三方会出现的问题?你是怎么处理的?本身有没有写过一些开源的框架?

   这类第三方问题也是千奇百怪,名气大的第三方必定要了解,多看下源代码,对提高颇有用!下面简单写个AFN; 

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

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

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

    AFHTTPRequestOperationManager 和 AFHTTPSessionManager :定义的 API(方法名称)是如出一辙,没有任何区别.

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

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

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

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

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

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

    AFXMLParserResponseSerializer; XML解析器;

    其它的再也不则过多赘述;

 

4.基础问题

  基础问题,看似简单,其余里面有不少的坑,一不当心就会掉进去;

 

  —>你对iOS内存管理怎么理解的?

    两个小思考:

      ①过分使用 block 以后,没法解决循环引用问题。

      ②遇到底层 Core Foundation 对象,须要本身手工管理它们的引用计数时,显得束手无策

    远古时代的MRC,到后来2011年WWDC推出的ARC,到2013年苹果废除macOS上的垃圾回收,用ARC代替,ARC才真正的崛起;

    一个重要的概念:引用计数;—->一个简单有效的管理对象的生命周期的方式;

    当咱们建立一个新对象的时候,它的引用计数为 1,当有一个新的指针指向这个对象时,咱们将其引用计数加 1,当某个指针再也不指向这个对象是,咱们将其引用计数减 1,当对象的引用计数变为 0 时,说明这个对象再也不被任何指针指向了,这个时候咱们就能够将对象销毁,回收内存。因为引用计数简单有效,除了 Objective-C 和 Swift 语言外,微软的 COM(Component Object Model )、C++11(C++11 提供了基于引用计数的智能指针 share_prt)等语言也提供了基于引用计数的内存管理方式。

  —->iOS内存之一:循环引用;

    若是A和B两个对象互相持有了对方做为本身的成员变量,只有当本身销毁的时候,才会将成员变量的引用计数减一,A依赖于B销毁,B依赖于A销毁,就会出现循环引用问题;不止两对象存在循环引用问题,多个对象依次持有对方,形式一个环状,也能够形成循环引用问题,并且在真实编程环境中,环越大就越难被发现。

    解决循环引用问题主要有两个办法:

    第一个办法是我明确知道这里会存在循环引用,在合理的位置主动断开环中的一个引用,使得对象得以回收。不过,主动断开循环引用这种操做依赖于程序员本身手工显式地控制,至关于回到了之前 “谁申请谁释放” 的内存管理年代,它依赖于程序员本身有能力发现循环引用而且知道在什么时机断开循环引用回收内存(这一般与具体的业务逻辑相关),因此这种解决方法并不经常使用,更常见的办法是使用弱引用 (weak reference) 的办法弱引用的实现原理是这样,系统对于每个有弱引用的对象,都维护一个表来记录它全部的弱引用的指针地址。当一个对象的引用计数为 0 时,系统就经过这张表,找到全部的弱引用指针,继而把它们都置成 nil。

    从这个原理中,咱们能够看出,弱引用的使用是有额外的开销的。虽然这个开销很小,可是若是一个地方咱们确定它不须要弱引用的特性,就不该该盲目使用弱引用。举个例子,有人喜欢在手写界面的时候,将全部界面元素都设置成 weak 的,这某种程度上与 Xcode 经过 Storyboard 拖拽生成的新变量是一致的。可是我我的认为这样作并不太合适。

    由于咱们在建立这个对象时,须要注意临时使用一个强引用持有它,不然由于 weak 变量并不持有对象,就会形成一个对象刚被建立就销毁掉。大部分 ViewController 的视图对象的生命周期与 ViewController 自己是一致的,没有必要额外作这个事情。

    早先苹果这么设计,是有历史缘由的。在早年,当时系统收到 Memory Warning 的时候,ViewController 的 View 会被 unLoad 掉。这个时候,使用 weak 的视图变量是有用的,能够保持这些内存被回收。可是这个设计已经被废弃了,替代方案是将相关视图的 CALayer 对应的 CABackingStore 类型的内存区会被标记成 volatile 类型,通常的内存泄漏问题,能够经过Xcode自带的instruments进行检测;

 

  —->iOS内存之二  Core Foundation 对象的内存管理

   底层的 Core Foundation 对象,在建立时大多以 XxxCreateWithXxx 这样的方式建立,例如:

    // 建立一个 CFStringRef 对象

    CFStringRef str= CFStringCreateWithCString(kCFAllocatorDefault, “hello world", kCFStringEncodingUTF8);

      // 建立一个 CTFontRef 对象

    CTFontRef fontRef = CTFontCreateWithName((CFStringRef)@"ArialMT", fontSize, NULL);

   对于这些对象的引用计数的修改,要相应的使用 CFRetain 和 CFRelease 方法。以下所示:

    // 建立一个 CTFontRef 对象

    CTFontRef fontRef = CTFontCreateWithName((CFStringRef)@"ArialMT", fontSize, NULL);

    // 引用计数加 1

    CFRetain(fontRef);

    // 引用计数减 1

    CFRelease(fontRef);

     对于 CFRetain 和 CFRelease 两个方法,能够直观地认为,这与 Objective-C 对象的 retain 和 release 方法等价。因此对于底层 Core Foundation 对象,咱们只须要延续之前手工管理引用计数的办法便可。

    除此以外,还有另一个问题须要解决。在 ARC 下,咱们有时须要将一个 Core Foundation 对象转换成一个 Objective-C 对象,这个时候咱们须要告诉编译器,转换过程当中的引用计数须要作如何的调整。这就引入了bridge相关的关键字,如下是这些关键字的说明:

    __bridge: 只作类型转换,不修改相关对象的引用计数,原来的 Core Foundation 对象在不用时,须要调用 CFRelease 方法。

    __bridge_retained:类型转换后,将相关对象的引用计数加 1,原来的 Core Foundation 对象在不用时,须要调用 CFRelease 方法。

    __bridge_transfer:类型转换后,将该对象的引用计数交给 ARC 管理,Core Foundation 对象在不用时,再也不须要调用 CFRelease 方法。 

    咱们根据具体的业务逻辑,合理使用上面的 3 种转换关键字,就能够解决 Core Foundation 对象与 Objective-C 对象相对转换的问题了。

 

    在 ARC 的帮助下,iOS 开发者的内存管理工做已经被大大减轻,可是咱们仍然须要理解引用计数这种内存管理方式的优势和常见问题,特别要注意解决循环引用问题。对于循环引用问题有两种主要的解决办法,一是主动断开循环引用,二是使用弱引用的方式避免循环引用。对于 Core Foundation 对象,因为不在 ARC 管理之下,咱们仍然须要延续之前手工管理引用计数的办法。

    在调试内存问题时,Instruments 工具能够很好地对咱们进行辅助,善用 Instruments 能够节省咱们大量的调试时间。

 

—>ARC和MRC怎么理解的?

    MRC的初衷和实现方法

    任何一个内存对象由系统本身处理释放的问题,不管建立者也好,持有者也好,不须要去考虑别人是否还在使用同一个内存对象,作好本身该作的就是了,别人的事情别人负责。这个方法是为了解决C/C++传统的内存管理方式中内存随着时间或人员变动形成的臃肿不能处理的问题; 

    理解之一:

      修饰符使用:

      控件使用weak修饰,代理用weak修饰,控件用weak修饰是由于已经有了一个强引用的存在,代理用weak是为了防止循环引用的存在;

      当修饰可变类型的属性时,如NSMutableArray、NSMutableDictionary、 NSMutableString,用strong。

      当修饰不可变类型的属性时,如NSArray、NSDictionary、NSString,用copy。

      由于copy出来的是一个新的,可变的变为不可变的 ,操做就会crash;(这点很重要~)

     理解之二:

      管理....(我还在总结....)

  

  —>控制器的生命周期是什么?开发的时候要注意什么?

      //类的初始化方法

      + (void)initialize;

      //对象初始化方法

      - (instancetype)init;

      //从归档初始化

      - (instancetype)initWithCoder:(NSCoder *)coder;

      //加载视图

      - (void)loadView;

      //将要加载视图

      - (void)viewDidLoad;

      //将要布局子视图

      -(void)viewWillLayoutSubviews;

      //已经布局子视图

      -(void)viewDidLayoutSubviews;

      //内存警告

      - (void)didReceiveMemoryWarning;

      //已经展现

      -(void)viewDidAppear:(BOOL)animated;

      //将要展现

      -(void)viewWillAppear:(BOOL)animated;

      //将要消失

      -(void)viewWillDisappear:(BOOL)animated;

      //已经消失

      -(void)viewDidDisappear:(BOOL)animated;

      //被释放

      -(void)dealloc;

    几个注意事项:

      ①:initialize函数并不会每次建立对象都调用,只有在这个类第一次建立对象时才会调用,作一些类的准备工做,再次建立这个类的对象,initalize方法将不会被调用,对于这个类的子类,若是实现了initialize方法,在这个子类第一次建立对象时会调用本身的initalize方法,以后不会调用,若是没有实现,那么它的父类将替它再次调用一下本身的initialize方法,之后建立也都不会再调用。所以,若是咱们有一些和这个相关的全局变量,能够在这里进行初始化。

    ②:init方法和initCoder方法类似,只是被调用的环境不同,若是用代码进行初始化,会调用init,从nib文件或者归档进行初始化,会调用initCoder。

    ③:loadView方法是开始加载视图的起始方法,除非手动调用,不然在ViewController的生命周期中没特殊状况只会被调用一次。

    ④:viewDidLoad方法是咱们最经常使用的方法的,类中成员对象和变量的初始化咱们都会放在这个方法中,在类建立后,不管视图的展示或消失,这个方法也是只会在将要布局时调用一次。

 

    —>说一下你所了解的iOS的SDK.

      这个是个坑,不太了解iOS通常都会说错,一句话归纳:

      Xcode是一个集成开发环境(IDE),它里面有软件开发工具(SDK),软件开发工具(SDK)中包含应用程序编程接口(API)补充一些,Cocoa Touch由苹果公司提供的软件开发api,也是苹果公司针对iPhone应用程序快速开发提供的一个类库。此库以一系列框架库的形式存在,支持开发人员使用用户界面元素构建图像化的事件驱动的应用程序。而Cocoa是苹果公司为Mac OS X所建立的原生面向对象的API,苹果的面向对象开发框架,用来生成 Mac OS X 的应用程序。

      其次SDK(Software  Development  Kit)软件开发工具,Xcode、iPhone模拟器、Interface Builder、Instruments和API集合等一些开发相关的工具等都属于SDK,iOS SDK最开始是独立于Xcode发布的,可是后来和Xcode绑定一块儿发布了,即在近期版本的Xcode中已经集成了iOS SDK。

而后IDE(Integrated Development  Environment)被集成好的开发环境,Xcode就是一个iOS的IDE,是一个集成了开发工具(SDK)的IDE。

最后Xcode,也是咱们最为熟知的,它是运行在操做系统Mac OS X上的IDE,是一个开发环境,开发平台,是开发OS X APP 和 iOS APP的最快捷的方式。

 

    —>如何自定义control?

 

      纯代码方法:自定义control

        initWithFrame:中添加子控件

         layoutSubviews中设置子控件frame。

        对外设置数据接口,重写setter方法给子控件设置显示数据。

        在view controller里面使用init/initWithFrame:方法建立自定义类,而且给自定义类的frame赋值。

        对自定义类对外暴露的数据接口进行赋值便可。

      xib方法:

         建立xib,在xib中拖入须要添加的控件并设置好尺寸。而且要将这个xib的Class设置为咱们的自定义类。

         经过IBOutlet的方式,将xib中的控件与自定义类进行关联。对外设置数据接口,重写setter方法给子控件设置显示数据。

         在view controller类里面加载xib文件就能够获得对应的类(这里不须要再设置自定义类的frame,由于xib已经有了整个view的大小。只须要设置位置。),接着就能够对类对外的数据接口赋值。

 

  —>开发中strong和weak的使用标准是什么?弱指针被释放后变成了什么?

    详见上面arc和mrc理解;

  

  —>说一下事件响应者链.

    先明确几个概念

      响应链:虚拟的不存的.是由多个响应者构成层次结构;

      响应者:是具备响应和处理事件能力的对象,UIResponder是全部响应者的基类;

      事件: 对于iOS设备用户来讲,触摸屏幕、晃动设备、经过遥控设施控制设备。

 

        触屏事件(Touch Event)

        运动事件(Motion Event)

        远端控制事件(Remote-Control Event

 

      响应者链一般是由视图(UIView)构成的;一个视图的下一个响应者是它视图控制器(UIViewController)(若是有的话),而后再转给它的父视图(Super View);视图控制器(若是有的话)的下一个响应者为其管理的视图的父视图;单例的窗口(UIWindow)的内容视图将指向窗口自己做为它的下一个响应者,须要指出的是,单例的应用(UIApplication)是一个响应者链的终点,它的下一个响应者指向nil,以结束整个循环。

 

      事件分发机制:专业的术语请查阅文档,我先作简单的概述.

        ①hit-test view

          当iOS系统检测到手指触摸(Touch)操做时会将其打包成一个UIEvent对象,并放入当前活动Application的事件队列,单例的UIApplication会从事件队列中取出触摸事件并传递给单例的UIWindow来处理,UIWindow对象首先会使用hitTest:withEvent:方法寻找这次Touch操做初始点所在的视图(View),即须要将触摸事件传递给其处理的视图,这个过程称之为hit-test view。

        ②hitTest:withEvent

          UIWindow实例对象会首先在它的内容视图上调用hitTest:withEvent:,此方法会在其视图层级结构中的每一个视图上调用pointInside:withEvent:(该方法用来判断点击事件发生的位置是否处于当前视图范围内,以肯定用户是否是点击了当前视图),若是pointInside:withEvent:返回YES,则继续逐级调用,直到找到touch操做发生的位置,这个视图也就是要找的hit-test view。

    hitTest:withEvent:方法的处理流程以下:

      首先调用当前视图的pointInside:withEvent:方法判断触摸点是否在当前视图内;

      若返回NO,则hitTest:withEvent:返回nil;

      若返回YES,则向当前视图的全部子视图(subviews)发送hitTest:withEvent:消息,全部子视图 的遍历顺序是从最顶层视图一直到到最底层视图,即从subviews数组的末尾向前遍历(采用递归方法,从索引值最大的开始),直到有子视图返回非空对象或者所有子视图遍历完毕;

      若第一次有子视图返回非空对象,则hitTest:withEvent:方法返回此对象,处理结束;

      如全部子视图都返回非,则hitTest:withEvent:方法返回自身(self)。

 

    注意点:

      1.若是最终hit-test没有找到第一响应者,或者第一响应者没有处理该事件,则该事件会沿着响应者链向上回溯,若是UIWindow实例和UIApplication实例都不能处理该事件,则该事件会被丢弃;

      2.hitTest:withEvent:方法将会忽略隐藏(hidden=YES)的视图,禁止用户操做(userInteractionEnabled=YES)的视图,以及alpha级别小于0.01(alpha<0.01)的视图。若是一个子视图的区域超过父视图的bound区域(父视图的clipsToBounds 属性为NO,这样超过父视图bound区域的子视图内容也会显示),那么正常状况下对子视图在父视图以外区域的触摸操做不会被识别,由于父视图的pointInside:withEvent:方法会返回NO,这样就不会继续向下遍历子视图了。固然,也能够重写pointInside:withEvent:方法来处理这种状况。

      3.咱们能够重写hitTest:withEvent:来达到某些特定的目的;

 

   —>通知,代理,block的区别,以及何时使用哪一个?为何?

      这个问题其实还能够加上一个KVO.....哈哈;

      代理,特色是一对一的形式,并且逻辑结构很是清晰。实现起来较为简单:写协议 ,设置代理这个属性,  而后在你想通知代理作事情的方法中调用便可。固然这里面有一些细节,包括 ①协议定义时,请用关键字@required,和@optional来明确代理是否必须实现某些方法 ②代理的类型需用id类型,并写明要遵照的协议 ③就是在调用代理方法的时候须要判断代理是否实现该方法。

      通知,通知的优势很明显,他是一对多的形式,并且能够在任意对象之间传递,不须要两者有联系,固然他的实现和代理相比较稍微绕一点,注册,发通知,收通知。这里面的注意点就是 ①对于系统没有定义的事件监听时须要本身发通知,这是你就须要定义一个key,字符串类型,这也是通知的一个弊端,你须要拷贝到收通知的对象,避免写错一个字母而没法收通知的尴尬 ②就是注册的通知中心须要手动移除,否则除了性能的问题还会有其余的问题出现,好比说一个控制器消失了以后还有由于某些事件而发出通知,形成不想要的结果。

      block功能比较强大,最大特色就是回调,并且回调时能够传入参数,最重要的是,不管在哪调用,block的执行都会回到block建立的地方执行,而非调用的地方。而block自己能够封装一段代码,一段代码你懂的,不少人在初学时会被搞晕,甚至在block的声明上就纠结,其实很正常,多用就好。语法的东西 ①声明分为3部分 返回值类型 + 变量名 + 参数 好比 成员变量的声明 void (^myblock)(int a)  

    我的见解:在公司的项目中通常是代理较多的,由于有不少复杂的逻辑;通知比较少用,由于通知太多容易出问题,block通常只是回调使用;

        简而言之,你用着哪一个爽并且不会出问题,用着就是;

 

  —>说一下消息传递机制.

      KVO, delegate,通知,block,target-action 

      看上面....

 

  —>分类和类拓展的区别?

 

    分类可以作到的事情主要是:即便在你不知道一个类的源码状况下,向这个类添加扩展的方法。此外,分类可以保证你的实现类和其余的文件区分开。虽然Category不可以直接(注意:此处是”不可以直接”,也就是能够经过runtime的方法来给分类添加属性的!!!)为类添加新的成员变量,可是Category包含类的全部成员变量,即便是@private的。Category能够从新定义新方法,也能够override继承过来的方法。

类扩展就像匿名(也就是没有那个括号里面的名字CustomView)的分类同样,除了同样不一样的是,类扩展声明必须在@implementation在实现。

    分类和类扩展的类似之处是:均可觉得类添加一个额外的方法;

不一样之处在于:要添加额外方法,分类必须在第一个@interface中声明方法,而且在@implementation中提供实现,否则运行时出错。而类扩展,你添加的方法是一个required API,若是不去实现,编译器会警告,并且这个方法的声明能够不在第一个@interface中去声明。

 

  —>说一下运行时和运行循环,以及你在项目中是如何用运行时的?

 

    Runloop —运行循环 

    1)用来干吗的?

      是一个死循环,保证程序不退出。程序默认一个线程执行一个任务,执行完任务后该线程就over掉了,但主线程不行,主线程一over掉程序就没有了。主线程没有事情作的时候会进入休眠状态等待用户的交互,用户只要有了点击事件,睡眠状态下的runloop就会被唤醒。查找点击的位置,由谁来响应点击事件,把消息发送给对方的对象。

    2) 在程序开发中何时会用到runloop?

      >定时器(NSTimer 和 CADisplayLink)

      >苹果公开提供的Mode有两个:KCRunLoopDefaultMode(默认等待用户交互的) 和 KCTrackingLoopDefaultMode(专门处理滚动视图的拖动事件)

     目的:保证程序不退出,监听全部事件!(触摸/时钟/网络)

 

      开发使用:

        >实例化时钟,添加到运行循环。

        注意:必定要销毁时钟,不然会产生循环引用!

 

      >socket 开发,使用runloop 可以监听网络端口数据的接收与发送状况!

          socket 开发,一般用在智能家居开发/游戏机。

        - 有不少文章介绍 运行循环的实战, 都会举例 AFN 2.0的时候 NSURLConnectionURL

        -必需要了解到“自动释放池”的释放与建立是与runloop有关的!

 

    RunTime—运行时   “消息机制”

 

    >程序启动时,首先加载运行时!是OC的底层。

      运行时的应用场景:

      1)关联对象。仿SDWebImage时,给分类动态添加属性。作到更好的解耦。简化使用。

      2)*动态获取类的属性。字典转模型使用!创建NSObject的分类。

        >2.1class_copyPropertyList 获取类属性数组

          >遍历数组

        >2.2property_getName  得到每个属性的名称

          >添加到OC的数组

          >free  释放运行时数组

 

    —>怎么监听tableview的移动?

      常见的通常方法是:一般是用KVO或者在scrollViewDidScroll的代理方法中监听ScrollView/TableView的contentOffset方法来设置导航栏透明度或者是拉伸顶部图片等操做;

      常见的姿式是在scrollViewDidScroll的代理方法中监听scrollView.contentOffset.y,会发现有导航栏时scrollView.contentOffset.y初始值可能会等于-64,若是再手动设置tableView.contentInset这个值又会改变,这个时候就须要计算出初始偏移量,而后再算偏移的差值,要是过几天再改下需求......从新计算 

 

 

5.项目经验问题

    —>app上架后,出现闪退bug如何处理?

 

    使用第三方的工具(好比腾讯的bugly),采用hotfix—jspatch解决,闪退的缘由有好多,

      1)内存问题—>能够经过Instruments工具中的Allocations 和 Leaks模块库来发现内存分配问题和内存泄漏问题。

      2)响应超时,能够看下crash日志

      3)应用逻辑的bug,这类bug是闪退的主要缘由,能够分析下崩溃日志来查找;

 

    —>你所维护的app的崩溃率是多少?怎么统计的?

        和上个问题基本差很少

 

    —>开发过程当中遇到的比较难处的bug是什么?

      本身的bug本身最清楚......

      像什么新老版本之中有些技术已通过时了,却在老项目中还继续存在,固然会有问题....

  

    —>你是怎么作的支付?

        支付类,一句话”好好看,要听话”;

        集成支付的东西,首要看”业内大哥”(支付宝,微信,银联…)的官方文档,让怎么作就怎么作!!!

 

    —>怎么处理token值过时?

        简单来讲,token值是用来标识用户的一个值;即让服务器知道”你是谁?”

        若是 app 是新闻类/游戏类/聊天类等须要长时间用户粘性的. 通常能够设置1年的有效时间!若是 app 是 支付类/银行类的. 通常token只得有效时间比较短: 15分钟左右!

       token值 失效后 会从新进行登陆;用户体检很差,能够增长一个时间字段记录token值将要过时时间,而后在快要过期间里用户打开app的时候,设定从新登陆;

 

     最后,↖(^ω^)↗,加油吧 少年!

相关文章
相关标签/搜索