美文网首页
回顾OC基础2

回顾OC基础2

作者: 懒惰的习惯 | 来源:发表于2019-03-02 17:16 被阅读0次
    // 1. _objc_MsgForward函数是做什么的?直接调用它,会发生什么?
    /** 我的看法:
     *  1> _objc_MsgForward函数是一个IMP,也即是一个方法实现,当一个方法并没有被实现的时
           候,会经过几个过程,其中之一就是_objc_MsgFordward,抓发给对应的对象去实现它
     *  2> 直接调用会造成,原先实现的方法不管用,而直接调用_objc_MsgForward方法的实现。
     */
    
    // 2. 能否向编译编译后得到的类中添加实例变量?能否向运行时创建的类中添加实例变量?为什么?
    /** 我的看法:
     *  1> 不能向编译后得到的类中添加实例变量
     *  2> 能向运行时创建的类中添加实例变量
     *  原因:
     *  1> 因为编译后得到的类已经通过runtime确定了实例变量的内存大小和链表结构,同时也会调用
           runtime方法来实现strong、weak。
     *  2> 可以通过runtime中的class_addIvar,来添加实例变量,但要在class_allocateClassPair之后,class_registerClassPair之前。
     */
    
    // 3. runloop和线程有什么关系?
    /** 我的看法:
     *  1> 除了主线程和主runloop是默认启动外,其他的runloop都是需要手动启动的。
     *  2> 我们的应用之所以不崩溃就是因为主runloop一直在默认无限循环中,直到被破坏而程序关
           闭。
     *  3> runloop跟线程是相互协调、相互生存的,可以说,runloop是为线程而生,线程而死。在Foundation中可以通过[NSRunLoop currentRunLoop]来创建当前runloop
     */
    
    // 4. runloop的mode有啥作用?
    /** 我的看法:
     *  1> mode有4种:默认、启动、滚动、集合(common)这4种。
     *  2> 可以更好的给程序提供性能,合理的利用资源,比如在滚动的时候,进入滚动模式,让
           runloop中其他模式的代码暂停。
     */
    
    // 5. 为什么oc对象要放在堆中,而不是栈?
    /** 1> 如何实现一个栈OC对象?
     *   struct {
         Class isa;
         } fakeNSObject;
         fakeNSObject.isa = [NSObject class];
     
         NSObject *obj = (__bridge NSObject *)&fakeNSObject;
         NSLog(@"obj = %@", [obj description]); // 栈对象
     
         NSObject *obj2 = [[NSObject alloc] init];
         NSLog(@"obj2 = %@", [obj2 description]); // 堆对象
     *  2> 栈对象的生命周期固定,虽然不会造成内存泄漏,但是在{}结束后,栈对象就被pop出去了,
           不能被长时间引用
     *  3> 栈对象内存比较小,因为iOS自动管理,而且不会长时间引用,因此内存空间有限
     *  4> block实际上是一个栈对象,但在ARC中,会自动copy在堆中,MRC需要手动copy
     */
    
    // 6. instancetype和id的区别?
    /** 我的看法:
     *  1> instancetype只能作为方法的返回,不能做参数,而id都可以
     *  2> instancetype返回的是本类对象(所在类),id是未可知类对象
     *  3> instancetype可以更好的为开发者在编译阶段时处理语法错发,而id可以更好的实现对象的
           传递
     */
    
    // 7. objc是使用什么机制来管理对象内存的?
    /** 我的看法:
     *  1> 通过retainCount来管理的
     *  2> 无论在ARC中,还是MRC中,都是这样
     *  3> 在销毁对象时,ARC是在当前运行循环结束时,检查retainCount,如果为0就销毁,MRC是
           手动销毁。
     */
    
    // 8. 不手动指定@autoreleasepool,一个@autoreleasepool什么时候释放?(以一个viewDidLoad为例)
    /** 我的看法:
     *  1> 手动添加@autoreleasepool后,在{}结束了释放。
     *  2> 在主autoreleasepool下,当用户唤醒(系统事件)app时就自动开启运行循环,在当
           前运行循环结束时,释放autoreleasepool中的对象,给它发release。
     *  3> viewDidLoad中,如果添加autoreleasepool,则在{}结束后,释放,也就是在
           viewDidLoad运行完之前,如果是主autoreleasepool,则在当前运行循环结束后,释
           放。
     */
    
    // 9. BAD_ACCESS在什么情况下出现?
    /** 我的想法:
     *  1> 这叫悬垂指针,也就是访问了已经释放的内存,对已经释放的内存发送消息。
     */
    
    // 10. 苹果是如何实现autoreleasepool的?
    /** 我的看法:
     *  1> 苹果是通过3组数组来实现的pop、push、release。
     *  2> 也就是放入autoreleasepool的对象push进这个push数组。
     *  3> pop数组存放已经出autoreleasepool里的对象。
     *  4> release数组存放需要释放的对象。
     */
    
    // 11. 在block内如何修改block的外部变量?
    /** 我的看法:
     *  1> block在iOS中是放入堆内存的,所以除非主动释放,否则会一直存在内存中
     *  2> 不是全局变量、静态变量、__block修饰变量的一些block外部变量是放入栈内存中
     *  3> 而栈内存在iOS中只有1M,堆内存大很多,所以栈内存中的值,修改后也不会有效果,在
           block{}结束后就被释放掉了,属于值传递
     *  4> 要想对block外部变量的值进行修改,只有将外部变量值先放入堆内存中,才有效。
     */
    
    // 12. 使用系统api时,比如UIView的动画block是否也要注意循环引用?
    /** 我的看法:
     *  1> 使用系统api时,不带ivar参数的block一般是不用注意循环引用的,系统会做处理
     *  2> 如果使用了ivar的系统block,比如GCD的group,NSNotification等,要注意
     *  3> 可以用facebook的循环引用检测开源库,来检测一下。
     */
    
    // 13. GCD的队列分几种?
    /** 我的看法:
     *  1> 串行队列 serial dispatch queue
     *  2> 并发队列 concurrent dispatch queue
     */
    
    // 14. 如何用GCD同步若干个异步操作?
    /** 我的看法:
     *  1> 采用group
     *  2> group_async进行异步操作,队列用并发队列concurrent dispatch queue或全局队列
     *  3> 然后用group_notify合并一下操作里的内容
     */
    
    // 15. dispatch_barrier_async的作用是什么?
    /** 我的看法:
     *  1> dispatch_barrier_async是阻止当前并发队列的其他操作,等待队列中的任务完成
     *  2> 完成后,在执行dispatch_barrier_queue中的任务
     *  3> dispatch_barrier_async中的并发队列只能是自定义,如果是系统的全局队列会失效,dispatch_barrier_async的作用会跟dispatch_aysnc一样了。
     */
    
    // 16. 苹果为什么废弃dispatch_get_current_queue?
    /** 我的看法:
     *  1> 容易造成程序死锁
     */
    
    // 17. KVC的keypath中的集合运算符如何试用?
    /** 我的看法:
     *  1> 集合运算符必须使用在普通对象或集合对象上
     *  2> 集合运算符主要有@min、@max、@avg、@sum、@count
     *  3> 集合运算符的格式主要是普通对象中属性age,@"@sum.age"或集合对象中普通对象属性
           @"obj.@sun.age"。
     */
    
    // 18. KVO/KVC中的keypath一定是属性吗?
    /** 我的看法:
     *  1> kvc都可以
     *  2> kvo因为要触发observe,所以自动只支持属性,手动支持实例变量或ivar
     */
    
    // 19. category是如何实现的?
    /** 我的看法:
     *  1> category是运行时决定的,可以添加方法(包括类方法)、属性、但不能添加实例变量
     *  2> 实例变量是在编译时就已经决定了,编译时已经决定了对象的内存结构,如果添加实例变量会
           改变其内存结构。
     *  3> 如果利用运行时给对象添加方法,则需要在alloc之后,register之前
     *  4> category其实并没有覆盖掉原来的方法,只是排在了原来方法的前面,运行时在查到方法
           时,是按顺序查找,因此才会调用category里的方法实现。
     *  5> load方法是编译时决定的,在类、category里添加load方法,都会执行,只是执行顺序是
           根据编译顺序决定的。
     */
    
    // 20. GCD和NSOperation
    /** 我的看法:
     *  1> 这是多线程开发技术,这两者技术是跟多线程无关,因为iOS会自己操作多线程
     *  2> 多线程就是一个任务在一条线程上执行,还是分在多个线程,执行小任务,然后合成
     *  3> 多线程是不是越多越好?每开一个线程都要损失一定的性能和资源,它有自己的栈和寄存器
     *  4> 真正让多线程能提高效率的,是并行技术,它可以让并发任务利用并行技术,异步执行,这样
           才会合理的利用CPU
     *  5> GCD是C实现的,和NSOperation相比,效率会更高,并且大部分函数是线程安全的
     *  6> 其中GCD和NSOperation都封装了多线程,只开放给我们队列和任务,也就是我们根本不用管
           多线程的开启和死亡,这个技术会自己管理。
     *  7> GCD除了队列,还有一个同步、异步的概念,也就是顺序执行和同时执行,一般我们没有特殊
           要求,都用异步
     *  8> GCD的队列有系统给的,和自己创建这两种,一般我建议自己创建,因为自己创建在调试的时
           候会有名字,而且效率也会高很多,而且自己创建的不用管理内存资源,ARC会自己管理
     *  9> GCD有once、gruop、信号量、barrier、wait、after等技术
     *  10> NSOperation是封装了GCD的Foundation框架,基础功能比GCD要多,比如取消、依赖、
           暂停、优先级等,高级一点的是自定义NSOperation
     */
    
    // 21. lldb(gdb)常用的调试命令?
    /** 我的看法:
     *  1> po,打印对象
     *  2> breakpoint set .. 设置断点
     *  3> n 断点下一步
     */
    
    // 22. 出现BAD_ACCESS,如何调试
    /** 1> xcode设置僵尸对象
     *  2> 断点调试
     *  3> 利用runtime的responseToSelector方法,出现BAD_ACCESS时objc最后访问的一个方法
     */
    
    // 23. 如何理解函数式编程和响应式编程?
    /** 我的看法:
     *  1> 函数式编程就是点".",所有的一些方法调用,基本可以用点语法来代替,而出现少量的[],
           或基本没有。例如masonry
     *  2> 响应式编程就是一个值的变化引起了另一个的变化,比如a = b + c,只要b或c变化,a立马
           得到响应。比如RAC就是经典例子
     *  3> RAC就是将iOS原生的响应全部通过信号量(single)来接收,然后函数式编程,直接在后面的
           block当中处理响应事件,比如RACObserve(kvo),[text rac_textsingle](输入框
           值的更新的监听),组合信号的监听([RACsingle combineLatest]),按钮的监听[button rac_singleForControlEvents],代理的监听等等
     *  4> 重点注意rac中block的循环引用
     */
    
    // 24. drawInRect是内存恶鬼吗?
    /** 我的看法:
     *  1> drawInRect实际是采用上下文来处理你所画的图
     *  2> 当你的上下文太大,而每次又需要重新绘制时,内存就会占用很多
     *  3> UIView显示实际上是CALayer,而drawInRect所绘制的图,是一张一张的存储在CALayer
           上,当你需要显示哪张是就在CALayer上显示已缓存的那些图中的其中之一
     *  4> 因此当你采用drawInRect绘制图时,应当使上下文尽可能的小,主要跟scale * width *
           height 有关
     *  5> 如果上下文是在太大,可以使用专用图层(CAShaperLayer)代替
     */
    

    相关文章

      网友评论

          本文标题:回顾OC基础2

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