iOS面试题二

作者: 果哥爸 | 来源:发表于2018-03-03 21:50 被阅读127次

    选择题

    1: A, B, C, D

    image.png

    解答:

    loadView:当控制器的根视图view为空,且此view被访问时调用。
    viewDidLoad:loadView调用之后被调用。
    viewWillApear:当控制器根视图view被添加到父视图上时调用。
    viewDidUnload:iOS6.0之前,当内存警告时,先卸载视图,再调用viewDidUnload来释放内存。
    

    2: B, C

    image.png
    解答:
    B.把声明和实现都放到.h文件中,链接的时候会报错。
    声明和实现都放到.h文件.png
    错误.png

    C.一个文件(Person.h Person.m)可以定义一个多个类。

    image.png image.png

    3. D

    image.png
    解答:
    因为number是实例变量,但是printNumber是类方法,在类方法里面没办法直接使用实例变量。 image.png image.png

    4. D

    image.png

    解答:

    事件处理的整个流程:

    • 触摸屏幕产生触摸事件后,触摸事件会被添加到UIApplication管理的事件队列中(首先收到事件的是UIApplication);

    • UIApplication会从事件队列中取出最前面的事件,把事件传递给应用程序的主窗口(keywindow);

    • 主窗口会在视图层次结构中找到一个最合适的 view来处理该触摸事件。

    • 最合适的view会调用自己的 touches相关方法处理事件,同时最合适的view可以决定是否将事件顺着响应链上下抛通过nextResopnse传递到下个响应者。
      (备注:touches默认做法是将事件顺着响应链向上抛)

    这里点击一个button后:

    • 点击事件通过UIApplication传递给keywindowkeywindow在视图层次结构中找到最合适的view就是该button本身,来处理该点击事件。

    -button处理该点击事件,同时拒绝将该事件顺着响应链上下抛通过nextResopnse传递到下个响应者,因此button就是响应链的最后一个响应者。

    详见:史上最详细的iOS之事件的传递和响应机制-原理篇

    5: A

    image.png

    解答:

    dispatch_sync 表示一个同步线程
    
    dispatch_get_main_queue 表示运行在主线程中的主队列,这是一个串行队列。
    
    任务2是同步线程的任务。
    
    
    • 首先,执行任务1,这是肯定没问题的,只是接下来,程序遇到了同步线程,那么它会进入等待,等待任务2执行完,然后执行任务3.

    • 但是这是串行队列,主队列有任务来,当然会将任务加到对尾,然后FIFO原则执行任务。因此任务2就会被加到主队列最后,任务3排在任务2前面,这样问题来了:

    ** 由于同步线程的阻塞,任务3要等任务2执行完才能执行,任务2由于排在任务3后面,意味着任务2要在任务3执行完后才能执行,所以他们进入了相互等待的局面。**

    ** 如图所示 : **

    image

    详见:GCD 死锁 案例 分析

    6. A

    image.png

    NSString *path = NSHomeDirectory();是应用程序目录的路径,在该目录下有三个文件夹:Documents、Library、temp以及一个.app包!该目录下就是应用程序的沙盒,应用程序只能访问该目录下的文件夹!!!

    1. AppName.app 目录:这是应用程序的程序包目录,包含应用程序的本身。由于应用程序必须经过签名,所以您在运行时不能对这个目录中的内容进行修改,否则可能会使应用程序无法启动。

    2. Documents 目录:您应该将所有的应用程序数据文件写入到这个目录下。这个目录用于存储用户数据。该路径可通过配置实现iTunes共享文件。可被iTunes备份。
      只有用户生成的文件、其他数据及其他程序不能重新创建的文件,应该保存在/Documents目录下面,并将通过iCloud自动备份。
      一般用来存放应用中建立的文件, 如数据库文件, 或者程序中浏览的数据, 如果进行备份将会备份此文件夹内容

    3. Library 目录:这个目录下有两个子目录:

      • Preferences 目录:包含应用程序的偏好设置文件。您不应该直接创建偏好设置文件,而是应该使用NSUserDefaults类来取得和设置应用程序的偏好.

      • Caches 目录:用于存放应用程序专用的支持文件,保存应用程序再次启动过程中需要的信息。可以重新下载或者重新生成的数据应该保存在/Library /caches目录下面。举个例子,比如杂志、新闻、地图应用使用的数据库缓存文件和可下载内容应该保存到这个文件夹。

      • 可创建子文件夹,用来放置您希望被备份但不希望被用户看到的数据。该路径下的文件夹,除Caches以外,都会被iTunes备份。

    4. tmp 目录:这个目录用于存放临时文件,保存应用程序再次启动过程中不需要的信息。该路径下的文件不会被iTunes备份。尽管iCloud不会备份这些文件,但在应用使用完这些数据之后要注意随时删除,避免占用用户设备的空间。

    详见:iOS 沙盒目录中各个目录的作用

    7: A. C

    image.png

    B.本地推送在iOS7,不需要用户授权就可发出通知,而iOS8以后,必须用户授权才可以发出通知
    D.用户点击推送启动应用时,在application:didFinishLaunchingWithOptions:方法中可以通过[launchOptions objectForKey:UIApplicationLaunchOptionsRemoteNotificationKey];
    获得推送的userinfo.

    8. A

    image.png
    解答:
    loadView
    • loadView方法是用来负责创建UIViewControllerview

    • 在每次访问UIViewControllerview(比如controller.view、self.view)而且viewnilloadView方法就会被调用。

    • 默认调用[super loadView],该函数会先去查找与UIViewController相关联的xib文件,通过加载xib文件来创建UIViewControllerview;如果没有明显地传xib文件名,就会加载跟UIViewController同名的xib文件;如果没有找到相关联的xib文件,就会创建一个空白的UIView,然后赋值给UIViewControllerview属性.

    • 想要代码来创建UIViewControllerview,就要重写loadView方法,并且不需要调用[super loadView],因为若没有xib文件,[super loadView]默认会创建一个空白的UIView。我们既然要通过代码来自定义UIView,那么就没必要事先创建一个空白的UIView,以节省不必要的开销。正确的做法应该是这样:

    9: C

    image.png
    解答:

    详见:frame和bounds的区别

    10: B

    image.png
    解答:
    self.var = arr;会调用- (void)setVar:(NSArray *)arr,方法,所以会导致循环调用。

    简答题:

    1.

    image.png
    解答:
    a:
     typedef int (^FJTestBlock) (int a, int b);
     FJTestBlock block = ^(int a, int b) {
            return a + b;
        };
        
        block(4, 6);
    

    b: block在内存管理上需要注意循环引用。

    #import "FJTestViewController.h"
    
    
    typedef int (^FJTestBlock) (int a, int b);
    
    @interface FJTestViewController ()
    @property (nonatomic, copy) FJTestBlock testBlock;
    @end
    
    @implementation FJTestViewController
    
    - (void)viewDidLoad {
        [super viewDidLoad];
    
        self.testBlock = ^int(int a, int b) {
            NSLog(@"%@", self);
            return a + b;
        };
    }
    
    

    像这样,FJTestViewController 持有testBlocktestBlockBlock内部持有self,就造成了循环引用,无法释放。

    可以通过如下方式来避免循环引用:

        __weak typeof(self) weakSelf = self;
        self.testBlock = ^int(int a, int b) {
            __strong typeof(self) strongSelf = weakSelf;
            if (strongSelf) {
                NSLog(@"%@", strongSelf);
            }
            return a + b;
        };
    
    • block之前定义对self的一个弱引用weakSelf因为是弱引用,所以self被释放时weakSelf会变为nil;
    • block中引用该弱引用,考虑到多线程情况,通过强引用strongSelf来引用该弱引用,这时如果self不为nil就会retain self,以防止在block内部使用过程中self被释放。
    • block块中使用该强引用strongSelf,注意对strongSelf进行nil检测,因为多线程在弱引用weakSelf对强引用strongSelf赋值时,弱引用weakSelf可能已经为nil
    • 强引用strongSelfblock作用域结束之后,自动释放。

    详见:Block里面的weak-strong理解

    2.

    image.png
    解答:
        //利用GCD并行多个线程并且等待所有线程结束之后再执行其它任务
        dispatch_group_t tmpGroup = dispatch_group_create();
        
        dispatch_group_async(tmpGroup, dispatch_get_global_queue(0, 0), ^{
            // 并行执行的A
        });
        
        dispatch_group_async(tmpGroup, dispatch_get_global_queue(0, 0), ^{
            // 并行执行的B
        });
        
        // A 、B 执行完成之后
        dispatch_group_notify(tmpGroup, dispatch_get_global_queue(0, 0), ^{
            // 并行执行的C
        });
    

    3.

    image.png
    解答:
    SEL:类成员的方法指针,不同于C中的函数指针,SEL只是一个编号。
    IMP: 函数指针,指向我们定义的函数

    SELIMP的关系
    任何继承NSObject的类都会的得到runtime的支持,在类中有一个isa指针,指向该类定义的成员组成的结构体,这个结构体是编译时编译器为(NSObject)类创建的,在这个结构体中包含一个指向父类的指针和一个Dispatch table(分发表),这个Dispatch table指明了SELIMP 的对应关系。

    4.

    image.png

    解答:

    #import "FJTestViewController.h"
    
    BOOL globalFlag = NO;
    
    @interface FJTestViewController ()
    // 队列
    @property (nonatomic, strong) dispatch_queue_t queue;
    @end
    
    @implementation FJTestViewController
    
    - (void)viewDidLoad {
        [super viewDidLoad];
        
        self.queue = dispatch_queue_create("test.queue", DISPATCH_QUEUE_SERIAL);
        for(NSInteger tmpIndex = 0; tmpIndex < 10; tmpIndex++) {
            dispatch_async(self.queue, ^{
                if (globalFlag) {
                    return ;
                }
                NSLog(@"%ld", (long)tmpIndex);
            });
        }
        
    
    
    }
    
    - (void)viewDidDisappear:(BOOL)animated {
        [super viewDidDisappear:animated];
        globalFlag = YES;
    }
    
    @end
    

    通过添加全局变量globalFlag来判断,默认设置globalFlagNO,如果页面退出,将globalFlag设置为YES,然后在异步里面判断如果globalFlagYES,就直接return.

    5.

    image.png
    解答:

    当执行该方法是会出现: 程序崩溃

    原因:

    • dealloc函数中会调用objc_clear_deallocating方法,来清空引用计数表并清除弱引用表,将所有weak引用指nil

    • __weak __typeof(self) weakSelf = self;·该赋值操作,会调用objc_initWeak函数,该函数会调用weak_register_no_lock为新对新添加注册操作,weak_register_no_lock内部会判断该对象是否在deallocating,如果改对象处于deallocating状态,就调用_objc_fatal函数,最后调用abort_with_reason函数来中断程序运行。

    详见:
    iOS 底层解析weak的实现原理(包含weak对象的初始化,引用,释放的分析)
    ARC下dealloc过程及.cxx_destruct的探究

    相关文章

      网友评论

        本文标题:iOS面试题二

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