美文网首页
iOS面试题下

iOS面试题下

作者: forvert | 来源:发表于2016-03-26 00:16 被阅读81次

    面试题下

    1. _objc_msgForward函数是做什么的,直接调用它将会发生什么?

      • _objc_msgForward是 IMP 类型,用于消息转发的:当向一个对象发送一条消息,但它并没有实现的时候,_objc_msgForward会尝试做消息转发。
      • 我们可以这样创建一个_objc_msgForward对象:
      IMP msgForwardIMP = _objc_msgForward;
      
      • 在“消息传递”过程中,objc_msgSend的动作比较清晰:首先在 Class 中的缓存查找 IMP (没缓存则初始化缓存),如果没找到,则向父类的 Class 查找。如果一直查找到根类仍旧没有实现,则用_objc_msgForward函数指针代替 IMP 。最后,执行这个 IMP 。
    2. 能否向编译后得到的类中增加实例变量?能否向运行时创建的类中添加实例变量?为什么?

      • 不能向编译后得到的类中增加实例变量;
        • 因为编译后的类已经注册在 runtime 中,类结构体中的 objc_ivar_list 实例变量的链表 和 instance_size 实例变量的内存大小已经确定,同时runtime 会调用 class_setIvarLayout 或 class_setWeakIvarLayout 来处理 strong weak 引用。所以不能向存在的类中添加实例变量;
      • 能向运行时创建的类中添加实例变量;
        • 运行时创建的类是可以添加实例变量,调用 class_addIvar 函数。但是得在调用 objc_allocateClassPair 之后,objc_registerClassPair 之前,原因同上。
    3. runloop和线程有什么关系?

      • Run loops是线程的基础架构部分
      • runloop 和线程的关系
        • 主线程的run loop默认是启动的。
        int main(int argc, char * argv[]) {
        

    @autoreleasepool {
    return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
    }
    }
    - 重点是UIApplicationMain()函数,这个方法会为main thread设置一个NSRunLoop对象,这就解释了:为什么我们的应用可以在无人操作的时候休息,需要让它干活的时候又能立马响应 - 对其它线程来说,run loop默认是没有启动的,如果你需要更多的线程交互则可以手动配置和启动,如果线程只是去执行一个长时间的已确定的任务则不需要。 - 在任何一个 Cocoa 程序的线程中,都可以通过以下代码来获取到当前线程的 run loop 。objc
    NSRunLoop *runloop = [NSRunLoop currentRunLoop];
    ```
    - 网页链接:runloop

    1. runloop的mode作用是什么?
      • model 主要是用来指定事件在运行循环中的优先级的,分为
      NSDefaultRunLoopMode(kCFRunLoopDefaultMode):默认,    空闲状态
      UITrackingRunLoopMode:ScrollView滑动时
      UIInitializationRunLoopMode:启动时
      NSRunLoopCommonModes(kCFRunLoopCommonModes):Mode集合
      
      
      • 苹果公开提供的 Mode 有两个:
      NSDefaultRunLoopMode(kCFRunLoopDefaultMode)
      

    NSRunLoopCommonModes(kCFRunLoopCommonModes)
    ```

    1. 以+ scheduledTimerWithTimeInterval...的方式触发的timer,在滑动页面上的列表时,timer会暂定回调,为什么?如何解决?
      • RunLoop只能运行在一种mode下,如果要换mode,当前的loop也需要停下重启成新的。利用这个机制,ScrollView滚动过程中NSDefaultRunLoopMode(kCFRunLoopDefaultMode)的mode会切换到UITrackingRunLoopMode来保证ScrollView的流畅滑动:只能在NSDefaultRunLoopMode模式下处理的事件会受到ScrollView的滑动影响。
      • 如果我们把一个NSTimer对象以NSDefaultRunLoopMode(kCFRunLoopDefaultMode)添加到主运行循环中的时候, ScrollView滚动过程中会因为mode的切换,而导致NSTimer将不再被调度。
      • 同时因为mode还是可定制的,所以:Timer计时会被scrollView的滑动影响的问题可以通过将timer添加到NSRunLoopCommonModes(kCFRunLoopCommonModes)来解决。代码如下:
      //将timer添加到NSDefaultRunLoopMode中
      

    [NSTimer scheduledTimerWithTimeInterval:1.0
    target:self
    selector:@selector(timerTick:)
    userInfo:nil
    repeats:YES];
    //然后再添加到NSRunLoopCommonModes里
    NSTimer *timer = [NSTimer timerWithTimeInterval:1.0
    target:self
    selector:@selector(timerTick:)
    userInfo:nil
    repeats:YES];
    [[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];
    ```

    1. objc使用什么机制管理对象内存?

      • 通过 retainCount 的机制来决定对象是否需要释放。 每次 runloop 的时候,都会检查对象的 retainCount,如果retainCount 为 0,说明该对象没有地方需要继续使用了,可以释放掉了。
    2. ARC通过什么方式帮助开发者管理内存?

      • ARC相对于MRC,不是在编译时添加retain/release/autorelease这么简单。应该是编译期和运行期两部分共同帮助开发者管理内存。
    3. 使用block时什么情况会发生引用循环,如何解决?

      • 一个对象中强引用了block,在block中又使用了该对象,就会发射循环引用。 解决方法是将该对象使用__weak或者__block修饰符修饰之后再在block中使用。
        -id weak weakSelf = self; 或者 weak __typeof(&*self)weakSelf = self该方法可以设置宏
        -id __block weakSelf = self;
    4. 在block内如何修改block外部变量?

      • 默认情况下,在block中访问的外部变量是复制过去的,即:写操作不对原变量生效。但是你可以加上__block来让其写操作生效,示例代码如下:
      __block int a = 0;
      

    void (^foo)(void) = ^{
    a = 1;
    }
    f00();
    //这里,a的值被修改为1
    ```

    1. 使用系统的某些block api(如UIView的block版本写动画时),是否也考虑引用循环问题?

      • 系统的某些block api中,UIView的block版本写动画时不需要考虑,但也有一些api 需要考虑:

      • 所谓“引用循环”是指双向的强引用,所以那些“单向的强引用”(block 强引用 self )没有问题

      • 但如果你使用一些参数中可能含有 ivar 的系统 api ,如 GCD 、NSNotificationCenter就要小心一点:比如GCD 内部如果引用了 self,而且 GCD 的其他参数是 ivar,则要考虑到循环引用:

    2. GCD的队列(dispatch_queue_t)分哪两种类型?

      • 串行队列Serial Dispatch Queue
      • 并行队列Concurrent Dispatch Queue
    3. 如何用GCD同步若干个异步调用?(如根据若干个url异步加载多张图片,然后在都下载完成后合成一张整图)

      • 使用Dispatch Group追加block到Global Group Queue,这些block如果全部执行完毕,就会执行Main Dispatch Queue中的结束处理的block。
      dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
      

    dispatch_group_t group = dispatch_group_create();
    dispatch_group_async(group, queue, ^{ /*加载图片1 / });
    dispatch_group_async(group, queue, ^{ /
    加载图片2 / });
    dispatch_group_async(group, queue, ^{ /
    加载图片3 */ });
    dispatch_group_notify(group, dispatch_get_main_queue(), ^{
    // 合并图片
    });
    ```

    1. dispatch_barrier_async的作用是什么?

      • 在并行队列中,为了保持某些任务的顺序,需要等待一些任务完成后才能继续进行,使用 barrier 来等待之前任务完成,避免数据竞争等问题。 dispatch_barrier_async 函数会等待追加到Concurrent Dispatch Queue并行队列中的操作全部执行完之后,然后再执行 dispatch_barrier_async 函数追加的处理,等 dispatch_barrier_async 追加的处理执行结束之后,Concurrent Dispatch Queue才恢复之前的动作继续执行。
      • 注意:使用 dispatch_barrier_async ,该函数只能搭配自定义并行队列 dispatch_queue_t 使用。不能使用: dispatch_get_global_queue ,否则 dispatch_barrier_async 的作用会和 dispatch_async 的作用一模一样。
    2. addObserver:forKeyPath:options:context:各个参数的作用分别是什么,observer中需要实现哪个方法才能获得KVO回调?

      /*
      

    1 观察者,负责处理监听事件的对象
    2 观察的属性
    3 观察的选项
    4 上下文
    */
    [self.person addObserver:self forKeyPath:@"name" options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld context:@"Person Name"];
    objc
    // observer中需要实现一下方法:
    // 所有的 kvo 监听到事件,都会调用此方法

     1. 观察的属性
     2. 观察的对象
     3. change 属性变化字典(新/旧)
     4. 上下文,与监听的时候传递的一致
    
    - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context;
    ```
    
    1. 若一个类有实例变量 NSString *_foo ,调用setValue:forKey:时,可以以foo还是 _foo 作为key?

      • 都可以。
    2. KVC的keyPath中的集合运算符如何使用?

      • 必须用在集合对象上或普通对象的集合属性上
      • 简单集合运算符有@avg, @count , @max , @min ,@sum
      • 格式 @"@sum.age"或 @"集合属性.@max.age"
    3. KVC和KVO的keyPath一定是属性么?

      • KVO支持实例变量
    4. 如何调试BAD_ACCESS错误?

      • 重写object的respondsToSelector方法,现实出现EXEC_BAD_ACCESS前访问的最后一个object
      • 通过 Zombie
      • 设置全局断点快速定位问题代码所在行
      • Xcode 7 已经集成了BAD_ACCESS捕获功能:Address Sanitizer。 用法如下:在配置中勾选✅Enable Address Sanitizer
    5. lldb(gdb)常用的调试命令?

      • breakpoint 设置断点定位到某一个函数
      • n 断点指针下一步
      • po打印对象
      • 更多调试命令

    本文完全转自@《招聘一个靠谱的 iOS》

    相关文章

      网友评论

          本文标题:iOS面试题下

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