美文网首页
Peak面试题

Peak面试题

作者: MichealXXX | 来源:发表于2019-09-29 10:08 被阅读0次

    1.什么是arc?(arc是为了解决什么问题诞生的?)

    首先解释ARC: automatic reference counting自动引用计数。
    ARC几个要点:
    1.在对象被创建时 retain count +1,在对象被release时 retain count -1.当retain count 为0 时,销毁对象。
    2.程序中加入autoreleasepool的对象会由系统自动加上autorelease方法,如果该对象引用计数为0,则销毁。

    那么ARC是为了解决什么问题诞生的呢?这个得追溯到MRC手动内存管理时代说起。
    MRC下内存管理的缺点:
    1.当我们要释放一个堆内存时,首先要确定指向这个堆空间的指针都被release了。(避免提前释放)
    2.释放指针指向的堆空间,首先要确定哪些指针指向同一个堆,这些指针只能释放一次。(MRC下即谁创建,谁释放,避免重复释放)
    3.模块化操作时,对象可能被多个模块创建和使用,不能确定最后由谁去释放。
    4.多线程操作时,不确定哪个线程最后使用完毕

    2.请解释以下keywords的区别: assign vs weak, __block vs __weak

    assign适用于基本数据类型,weak是适用于NSObject对象,并且是一个弱引用。
    assign其实也可以用来修饰对象,那么我们为什么不用它呢?因为被assign修饰的对象在释放之后,指针的地址还是存在的,也就是说指针并没有被置为nil。如果在后续的内存分配中,刚好分到了这块地址,程序就会崩溃掉。
    而weak修饰的对象在释放之后,指针地址会被置为nil。所以现在一般弱引用就是用weak。
    首先__block是用来修饰一个变量,这个变量就可以在block中被修改(参考block实现原理)
    __block:使用__block修饰的变量在block代码快中会被retain(ARC下,MRC下不会retain)
    __weak:使用__weak修饰的变量不会在block代码块中被retain
    同时,在ARC下,要避免block出现循环引用 __weak typedof(self)weakSelf = self;

    3.__block在arc和非arc下含义一样吗?

    是不一样的。
    在MRC中__block variable在block中使用是不會retain的
    但是ARC中__block則是會Retain的。
    取而代之的是用__weak或是__unsafe_unretained來更精確的描述weak reference的目的
    其中前者只能在iOS5之後可以使用,但是比較好 (該物件release之後,此pointer會自動設成nil)
    而後者是ARC的環境下為了相容4.x的解決方案。

    4.使用nonatomic一定是线程安全的吗?

    不是的。
    atomic原子操作,系统会为setter方法加锁。 具体使用 @synchronized(self){//code }
    nonatomic不会为setter方法加锁。
    atomic:线程安全,需要消耗大量系统资源来为属性加锁
    nonatomic:非线程安全,适合内存较小的移动设备

    5.描述一个你遇到过的retain cycle例子。

    @property (nonatomic,strong)HttpRequestHandler * handler;
        @property (nonatomic,strong)NSData          *data;
        _handler = [httpRequestHandler sharedManager];
        [ downloadData:^(id responseData){
            _data = responseData;
        }];
    

    6.+(void)load; +(void)initialize;有什么用处?

    在Objective-C中,runtime会自动调用每个类的两个方法。+load会在类初始加载时调用,+initialize会在第一次调用类的类方法或实例方法之前被调用。这两个方法是可选的,且只有在实现了它们时才会被调用。
    共同点:两个方法都只会被调用一次。

    7.为什么其他语言里叫函数调用, objective c里则是给对象发消息

    [receiver message]会被编译器转化为:
    objc_msgSend(receiver, selector)
    如果消息含有参数,则为:
    objc_msgSend(receiver, selector, arg1, arg2, ...)

    如果消息的接收者能够找到对应的selector,那么就相当于直接执行了接收者这个对象的特定方法;否则,消息要么被转发,或是临时向接收者动态添加这个selector对应的实现内容,要么就干脆玩完崩溃掉。

    现在可以看出[receiver message]真的不是一个简简单单的方法调用。因为这只是在编译阶段确定了要向接收者发送message这条消息,而receive将要如何响应这条消息,那就要看运行时发生的情况来决定了。

    Objc Runtime使得C具有了面向对象能力,在程序运行时创建,检查,修改类、对象和它们的方法。可以使用runtime的一系列方法实现。

     struct objc_class {
        Class isa OBJC_ISA_AVAILABILITY; //isa指针指向Meta Class,因为Objc的类的本身也是一个Object,为了处理这个关系,r       untime就创造了Meta Class,当给类发送[NSObject alloc]这样消息时,实际上是把这个消息发给了Class Object
    
        #if !__OBJC2__
        Class super_class OBJC2_UNAVAILABLE; // 父类
        const char *name OBJC2_UNAVAILABLE; // 类名
        long version OBJC2_UNAVAILABLE; // 类的版本信息,默认为0
        long info OBJC2_UNAVAILABLE; // 类信息,供运行期使用的一些位标识
        long instance_size OBJC2_UNAVAILABLE; // 该类的实例变量大小
        struct objc_ivar_list *ivars OBJC2_UNAVAILABLE; // 该类的成员变量链表
        struct objc_method_list **methodLists OBJC2_UNAVAILABLE; // 方法定义的链表
        struct objc_cache *cache OBJC2_UNAVAILABLE; // 方法缓存,对象接到一个消息会根据isa指针查找消息对象,这时会在method       Lists中遍历,如果cache了,常用的方法调用时就能够提高调用的效率。
        struct objc_protocol_list *protocols OBJC2_UNAVAILABLE; // 协议链表
        #endif
    
        } OBJC2_UNAVAILABLE;
    

    向object发送消息时,Runtime库会根据object的isa指针找到这个实例object所属于的类,然后在类的方法列表以及父类方法列表寻找对应的方法运行。id是一个objc_object结构类型的指针,这个类型的对象能够转换成任何一种对象。

    详细叙述下消息发送步骤:
    检测这个 selector 是不是要忽略的。比如 Mac OS X 开发,有了垃圾回收就不理会 retain,release 这些函数了。
    检测这个 target 是不是 nil 对象。ObjC 的特性是允许对一个 nil 对象执行任何一个方法不会 Crash,因为会被忽略掉。
    如果上面两个都过了,那就开始查找这个类的 IMP,先从 cache 里面找,完了找得到就跳到对应的函数去执行。
    如果 cache 找不到就找一下方法分发表。
    如果分发表找不到就到超类的分发表去找,一直找,直到找到NSObject类为止。

    8.什么是method swizzling?

    在Objective-C中调用一个方法,其实是向一个对象发送消息,查找消息的唯一依据是selector的名字。利用Objective-C的动态特性,可以实现在运行时偷换selector对应的方法实现,达到给方法挂钩的目的。
    每个类都有一个方法列表,存放着selector的名字和方法实现的映射关系。IMP有点类似函数指针,指向具体的Method实现。

    9.UIView和CALayer是啥关系?

    1.UIView是iOS系统中界面元素的基础,所有的界面元素都继承自它。它本身完全是由CoreAnimation来实现的 (Mac下似乎不是这样)。它真正的绘图部分,是由一个叫CALayer(Core Animation Layer)的类来管理。 UIView本身,更像是一个CALayer的管理器,访问它的跟绘图和跟坐标有关的属性,例如frame,bounds等 等,实际上内部都是在访问它所包含的CALayer的相关属性。

    2.UIView有个layer属性,可以返回它的主CALayer实例,UIView有一个layerClass方法,返回主layer所使用的 类,UIView的子类,可以通过重载这个方法,来让UIView使用不同的CALayer来显示

    10.loadView是干嘛用的?

    当你访问一个ViewController的view属性时,如果此时view的值是nil,那么,ViewController就会自动调用loadView这个方法。这个方法就会加载或者创建一个view对象,赋值给view属性。
    loadView默认做的事情是:如果此ViewController存在一个对应的nib文件,那么就加载这个nib。否则,就创建一个UIView对象。
    如果你用Interface Builder来创建界面,那么不应该重载这个方法。

    如果你想自己创建view对象,那么可以重载这个方法。此时你需要自己给view属性赋值。你自定义的方法不应该调用super。如果你需要对view做一些其他的定制操作,在viewDidLoad里面去做。

    =========================================

    根据上面的文档可以知道,有两种情况:
    1、如果你用了nib文件,重载这个方法就没有太大意义。因为loadView的作用就是加载nib。如果你重载了这个方法不调用super,那么nib文件就不会被加载。如果调用了super,那么view已经加载完了,你需要做的其他事情在viewDidLoad里面做更合适。
    2、如果你没有用nib,这个方法默认就是创建一个空的view对象。如果你想自己控制view对象的创建,例如创建一个特殊尺寸的view,那么可以重载这个方法,自己创建一个UIView对象,然后指定 self.view = myView; 但这种情况也没有必要调用super,因为反正你也不需要在super方法里面创建的view对象。如果调用了super,那么就是浪费了一些资源而已

    11.viewWillLayoutSubView你总是知道的。

    横竖屏切换的时候,系统会响应一些函数,其中 viewWillLayoutSubviews 和 viewDidLayoutSubviews。

    - (void)viewWillLayoutSubviews
    
    {
    
         [self _shouldRotateToOrientation:(UIDeviceOrientation)[UIApplication sharedApplication].statusBarOrientation];
    
    }
    
    -(void)_shouldRotateToOrientation:(UIDeviceOrientation)orientation {
            if (orientation == UIDeviceOrientationPortrait ||orientation ==
                    UIDeviceOrientationPortraitUpsideDown) {
              // 竖屏
    }
    else {
             // 横屏
        }
    }
    

    12.GCD里面有哪几种Queue?你自己建立过串行queue吗?背后的线程模型是什么样的?

    1.主队列 dispatch_main_queue(); 串行 ,更新UI
    2.全局队列 dispatch_global_queue(); 并行,四个优先级:background,low,default,high
    3.自定义队列 dispatch_queue_t queue ; 可以自定义是并行:DISPATCH_QUEUE_CONCURRENT或者串行DISPATCH_QUEUE_SERIAL

    相关文章

      网友评论

          本文标题:Peak面试题

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