美文网首页
iOS 面试题

iOS 面试题

作者: _YZG_ | 来源:发表于2017-12-05 17:57 被阅读12次

    1.ARC 相对于GC的优点和缺点

    优点:1.ARC工作在编译期,在运行时没有额外开销。
       2.ARC的内存回收是平稳进行的,对象不被使用时会立即被回收。而GC的内存回收是一阵一阵的,回收时需要暂停程序,会有一定的卡顿。
    缺点:1.GC太简单了,基本上完全不用处理内存管理的问题,而ARC还是需要处理类似循环引用这种内存管理问题。
       2.GC一类的语言相对来说学习起来更简单。

    2.instancetype和id的异同

    • 相同点
      都可以作为方法的返回类型
    • 不同点
      1.instancetype可以返回和方法所在类相同类型的对象,id只能返回未知类型的对象;
      2.instancetype只能作为返回值,不能像id那样作为参数

    3.isKindOfClass和isMemberOfClass的区别

    isKindOfClass来确定一个对象是否是一个类的成员,或者是派生自该类的成员
    isMemberOfClass只能确定一个对象是否是当前类的成员

    4.load和initialize的区别

    load、initialize.png

    1.loadinitialize方法都会在实例化对象之前调用,以main函数为分水岭,前者在main函数之前调用,后者在之后调用。这两个方法会被自动调用,不能手动调用他们。
    2.loadinitialize方法都不用显示的调用父类的方法而是自动调用,即使子类没有initialize方法也会调用父类的的方法。而load方法则不会调用父类。
    3.load方法通常用来进行Method Swizzle,initialize方法一般用于初始化全局变量或静态变量。
    4.loadinitialize方法内部使用了锁,因此他们是线程安全的。实现时要尽可能保持简单,避免阻塞线程,不要再使用锁。
    http://www.jianshu.com/p/d25f691f0b07

    5.loadVIew是干什么用的?

    很多人都会疑惑self.view,这个view到底是哪里来的,就是在这里。一般不需要去操作这个。但如果有特殊的需求,要求这个self.view是我们自己自定义的view时候就可以用这个方法

     MyView *myview = [[MyView alloc]init];
      self.view = myview;
    

    像上面一样重写一下就行了。
    切记: 不要自己调用-loadVIew -viewDidLoad

    6.new 与 alloc/init区别

    alloc分配内存的时候使用了zone,它是给对象分配内存的时候,把关联的对象分配到一个相邻的内存区域内,以便于调用时消耗更少的代价,提升了程序处理速度

    为什么不推荐使用new?
    如果使用new的话,初始化方法被固定死只能调用init。而你想调用initXXX怎么办?没门儿!

    概括来说,new和alloc/init在功能上几乎是一致的,分配内存并完成初始化。
    差别在于,采用new的方法只能采用默认的init方法完成初始化,
    采用alloc的方式可以用其他定制的初始化方法。
    http://blog.csdn.net/lvxiangan/article/details/44906035

    7.OC是否可以实现多继承

    OC不可以多重继承,可以用代理来代替多继承的功能,可以遵守多个协议,用逗号隔开。
    也可以通过组合的方式实现
    实例 现在ClassC需要继承ClassA中methodA、ClassB中methodB

    @interface ClassC : NSObject {
      ClassA *a;
      ClassB *b;
    }
    
    -(id)initWithA:(ClassA *)A b:(ClassB *)B;
    
    -(void)methodA;
    -(void)methodB;
    
    @end
    
    @implementation  ClassC
    
    -(id)initWithA:(ClassA *)A b:(ClassB *)B{
    
           a=[[ClassA alloc] initWithClassA: A];//[A copy];
    
           b=[[ClassB alloc] initWithClassB: B];//[B copy];
    
    }
    
    -(void)methodA{
    
          [a methodA];
    
    }
    -(void)methodB{
    
          [b methodB];
    
    }
    

    8.深复制浅复制

    对于容器对象,发生深拷贝时对容器对象本身来说是深拷贝,因为产生了新对象,而对容器内的元素来说是浅拷贝。即:修改容器内的元素,无论是原来对象还是拷贝产生的新对象,两个容器内的元素都会发生变化,因为容器内存的是容器元素的内存地址。如果想让容器对象本身及容器内的元素都发生深拷贝,使用归档。先归档,再解档。

    浅 复 制:在复制操作时,对于被复制的对象的每一层复制都是指针复制。
    深 复 制:在复制操作时,对于被复制的对象至少有一层复制是对象复制。
    完全复制:在复制操作时,对于被复制的对象的每一层复制都是对象复制。

    retain:始终是浅复制。引用计数每次加一。返回对象是否可变与被复制的对象保持一致。

    copy:对于可变对象为深复制,引用计数不改变;对于不可变对象是浅复制,
    引用计数每次加一。始终返回一个不可变对象。

    mutableCopy:始终是深复制,引用计数不改变。始终返回一个可变对象。

    不可变对象:值发生改变,其内存首地址随之改变。
    可变对象:无论值是否改变,其内存首地址都不随之改变。
    引用计数:为了让使用者清楚的知道,该对象有多少个拥有者(即有多少个指针指向同一内存地址)。

    简化为:
    问:什么时候用到深浅拷贝?
    答:深拷贝是在要将一个对象从可变(不可变)转为不可变(可变)或者将一个对象内容克隆一份时用到;
    浅拷贝是在要复制一个对象的指针时用到。

    巨详细
    http://www.cnblogs.com/langtianya/p/3722129.html

    9.Copy到底什么时候用?

    在OC里面有个值对象的概念,当你新定义一个属性是值对象时就应该用copy来修饰。那么都什么对象是值对象呢?
    值对象: 指封装了基本值(属于 C 数据类型)且提供与该值相关的服务的对象。值对象以对象形式表示标量类型。Foundation 框架向您提供了以下类(这些类产生对象,用于字符串、二进制数据、日期与时间、数字以及其他值):
    NSString和NSMutableString , NSData和NSMutableData , NSDate , NSNumber , NSValue
    http://blog.csdn.net/u010664555/article/details/41786815
    http://www.jianshu.com/p/26210296fa02
    NSNumber和NSValue的简单使用
    http://blog.csdn.net/lushuner/article/details/48494493
    NSValue与@encode
    http://www.jianshu.com/p/0e6626d3614c

    还是参照下面吧

    @property内存管理策略的选择
    1.非ARC
    1> copy : 只用于NSString\block;
    2> retain : 除NSString\block以外的OC对象;
    3> assign : 基本数据类型、枚举、结构体(非OC对象),当2个对象相互引用,一端用retain,一端用assign。
    2.ARC

    1> copy : 只用于NSString\block;
    2> strong : 除NSString\block以外的OC对象;
    3> weak : 当2个对象相互引用,一端用strong,一端用weak;
    4> assgin : 基本数据类型、枚举、结构体(非OC对象)。
    https://my.oschina.net/aofe/blog/266677

    10.weak变量在引用计数为0时,会被自动设置为nil,这个特性是如何实现的?

    简单来说,系统有一个全局的CFMutalbeDictionary实例,来保存每个对象的weak指针列表,因为每个对象可能有多个weak指针,所以这个实例的值是CFMutableSet类型。

    剩下我们要做的,就是在引用计数变成0的时候,去这个全局的字典里面,找到所有的weak指针,将其值设置为nil。如何做到这一点呢?Friday QA上介绍了一种类似KVO实现的方式。当对象存在weak指针时,我们可以将这个实例指向一个新创建的子类,然后修改这个子类的release方法,在release方法中,去全局的CFMutableDictionary字典中找到所有的weak对象,并且设置为nil。

    11.响应者链

    事件沿着一个指定的路径传递直到它遇见可以处理它的对象。首先一个UIApplication对象从队列顶部获取一个事件并分发它以便处理。通常,它把事件传递给应用程序的关键窗口对象,该对象把事件传递给一个初始对象来处理。初始对象取决于事件的类型。

    如果父控件不能接收触摸事件,那么子控件就不可能接收到触摸事件

    事件的完整处理过程:
    1.先将事件对象由上往下传递(由父控件传递给子控件),找到最合适的控件来处理这个事件
    2.调用最合适控件的touches..方法
    3.如果调用了[super touches..]就会将事件顺着响应者链条往上传递,传递给上一个响应者
    4.接着就会调用上一个响应者的touches..方法

    上一个响应者:
    1.如果当前这个view是控制的view,那么控制器就是上一个响应者
    2.如果当前这个view不是控制器的view,那么父控件就是上一个响应者

    事件传递机制:
    1.当iOS程序中发生触摸事件后,系统会将事件加入到UIApplication管理的一个任务队列中
    2.UIApplication将处于任务队列最前端的事件向下分发。即UIWindow。
    3.UIWindow将事件向下分发,即UIView。
    4.UIView首先看自己是否能处理事件,触摸点是否在自己身上。如果能,那么继续寻找子视图。
    5.遍历子控件,重复以上两步。
    6.如果没有找到,那么自己就是事件处理者。
    7.如果自己不能处理,那么不做任何处理。
    其中 UIView不接受事件处理的情况主要有以下三种
    1)alpha <0.01
    2)userInteractionEnabled = NO
    3.hidden = YES

    回答:
    1.响应者链条是由多个响应者对象链接起来的链条(什么是响应者对象:能处理事件的对象)
    2.利用响应者链条,能让多个控件处理同一个触摸事件
    3.怎么利用链条往上传递?是是上一个响应者

    12.__block__weak修饰符的区别

    __block不管是ARC还是MRC模式下都可以使用,可以修饰对象,还可以修饰基本数据类型。
    __weak只能在ARC模式下使用,也只能修饰对象,不能修饰基本数据类型
    __block对象可以在block中被重新复制,__weak不可以。

    13.ARC内部原理

    ARC会自动帮我们插入retainrelease语句。ARC编译器有两部分,分别是前端编译器和优化器。

    1.前端编译器
    前端编译器会为“拥有的”每一个对象插入相应的release语句。如果对象的所有权修饰符是__strong,那么它就是被拥有的。如果在某个方法内创建了一个对象,前端编译器会在方法末尾自动插入release语句以销毁它。而类拥有的对象(实例变量/属性)会在dealloc方法内被释放。事实上,你并不需要些dealloc方法或调用父类的dealloc方法,ARC会自动帮你完成一切。此外,由编译器生成的代码甚至会比你自己写的release语句的性能还要好,因为编译器可以做出一些假设。在ARC中,没有类可以覆盖release方法,也没有调用它的必要。ARC会通过直接使用objc_release来优化调用过程。而对于retain也是同样的方法。ARC会调用objc_retain来取代保留消息。

    2.ARC优化器
    虽然前端编译器听起来很厉害的样子,但代码中有时仍会出现几个对retainrelease的重复调用。ARC优化器负责移除多余的retainrelease语句,确保生成的代码运行速度高于手动引用计数的代码。

    14.iOS ARC,IBOutlets strong与weak

    在ARC中,一般outlet属性都推荐使用weak,而File's Owner链接到Nib的顶层对象应该使用strong。通俗一点说就是:如果你自定义的view,不是做为主视图的子视图直接显示,而是你自己实例化创建出来并加入主视图里的,那么你需要自己保留对象的所有权,需要使用strong。

    15.UIView和CALayer区别和联系

    1.UIView是UIKit的(只能iOS使用)CALayer是QuartzCore的(iOS和MacOS通用)
    2.CALayer比UIView更加轻量级别,但是可以实现同样的效果
    3.UIView比CALayer多了一个事件处理的功能,也就是说,CALayer不能处理用户的触摸事件,而UIView可以
    4.UIView有个重要属性layer,可以返回它的主CALayer实例。CALayer *layer = myView.layer。
    6.坐标系统:CALayer的坐标系统比UIView多了一个anchorPoint属性。
    7.UIView是iOS系统中界面元素的基础,所有的界面元素都是继承自它。它本身完全是由CoreAnimation来实现的。它真正的绘图部分,是由一个CALayer类来管理 。UIView本身更像是一个CALayer的管理器,访问它的跟绘图和坐标有关的属性,例如frame,bounds等,实际上内部都是在访问它所包含的CALayer的相关属性。layer可以设置圆角显示(cornerRadius),也可以设置阴影(shadowColor)但是如果layer树中某个layer设置了圆角,树中所有layer的阴影效果都将不显示了。因此若是要有圆角又要阴影,变通方法只能做两个重叠的UIView,一个layer显示圆角,一个layer显示阴影。
    8.渲染 当更新层,改变不能立即显示在屏幕上。当所有的层都准备好时,可以调用setNeedsDisplay方法来重绘显示。
    9.变换 要在一个层中添加一个3D变换,可以分别设置层的transform或affineTransform属性。
    10.变形Quartz Core的渲染能力,使二维图像可以被自由操纵,就好像是三维的。图像可以在一个三维坐标系中以任意角度被旋转,缩放和倾斜。CATransform3D的一套方法提供了一些魔术般的变换效果。

    16.Runtime的消息机制

    首先,编辑器将代码[obj makeText]转换为objc_msgSend(obj,@selector(makeText));在objc_msgSend函数中。首先通过obj的isa指针找到obj对应的class。在class中先去cache中 通过SEL查找对应函数method(猜测cache中method列表是以SEL为key通过hash表来存储的,这样能提高函数查找速度),若cache中未找到。再去methodList中查找,若methodlist中未找到,则去superclass中查找。若能找到,则将method加入到cache中,以方便下次查找,并通过method中的函数指针跳转到对应的函数中去执行。

    相关文章

      网友评论

          本文标题:iOS 面试题

          本文链接:https://www.haomeiwen.com/subject/iekzwttx.html