iOS面试题

iOS最新面试题汇总(三)

2017-06-07  本文已影响1280人  寻常_0

iOS最新面试题汇总:
iOS最新面试题汇总(一)
iOS最新面试题汇总(二)
iOS最新面试题汇总(三)
iOS最新面试题汇总(四)

  1. 下面的代码输出什么?
    @implementation Son : Father
    - (id)init {
       if (self = [super init]) {
           NSLog(@"%@", NSStringFromClass([self class])); // Son
           NSLog(@"%@", NSStringFromClass([super class])); // Son
       }
       return self;
    }
    @end
    // 解析:
    self 是类的隐藏参数,指向当前调用方法的这个类的实例。
    super是一个Magic Keyword,它本质是一个编译器标示符,和self是指向的同一个消息接收者。
    不同的是:super会告诉编译器,调用class这个方法时,要去父类的方法,而不是本类里的。
    上面的例子不管调用[self class]还是[super class],接受消息的对象都是当前 Son *obj 这个对象。
  1. 写一个完整的代理,包括声明、实现
    // 创建
    @protocol MyDelagate
    @required
    -(void)eat:(NSString *)foodName; 
    @optional
    -(void)run;
    @end

    //  声明 .h
    @interface person: NSObject<MyDelagate>

    @end

    //  实现 .m
    @implementation person
    - (void)eat:(NSString *)foodName { 
       NSLog(@"吃:%@!", foodName);
    } 
    - (void)run {
       NSLog(@"run!");
    }

    @end
  1. isKindOfClass、isMemberOfClass、selector作用分别是什么
    isKindOfClass:作用是某个对象属于某个类型或者继承自某类型。
    isMemberOfClass:某个对象确切属于某个类型。
    selector:通过方法名,获取在内存中的函数的入口地址。

4. ####delegate 和 notification 的区别

    1). 二者都用于传递消息,不同之处主要在于一个是一对一的,另一个是一对多的。
    2). notification通过维护一个array,实现一对多消息的转发。
    3). delegate需要两者之间必须建立联系,不然没法调用代理的方法;notification不需要两者之间有联系。
  1. 什么是block?
    闭包(block):闭包就是获取其它函数局部变量的匿名函数。
  1. block反向传值

    在控制器间传值可以使用代理或者block,使用block相对来说简洁。

    在前一个控制器的touchesBegan:方法内实现如下代码。

      // OneViewController.m
      TwoViewController *twoVC = [[TwoViewController alloc] init];
      twoVC.valueBlcok = ^(NSString *str) {
        NSLog(@"OneViewController拿到值:%@", str); 
      };
      [self presentViewController:twoVC animated:YES completion:nil];

      // TwoViewController.h   (在.h文件中声明一个block属性)
      @property (nonatomic ,strong) void(^valueBlcok)(NSString *str);

      // TwoViewController.m   (在.m文件中实现方法)
    - (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
        // 传值:调用block
        if (_valueBlcok) {
            _valueBlcok(@"123456");
        }
    }
  1. block的注意点
    1). 在block内部使用外部指针且会造成循环引用情况下,需要用__week修饰外部指针:
        __weak typeof(self) weakSelf = self; 
    2). 在block内部如果调用了延时函数还使用弱指针会取不到该指针,因为已经被销毁了,需要在block内部再将弱指针重新强引用一下。
        __strong typeof(self) strongSelf = weakSelf;
    3). 如果需要在block内部改变外部栈区变量的话,需要在用__block修饰外部变量。
  1. BAD_ACCESS在什么情况下出现?
    答:这种问题在开发时经常遇到。原因是访问了野指针,比如访问已经释放对象的成员变量或者发消息、死循环等。
  1. lldb(gdb)常用的控制台调试命令?
    1). p 输出基本类型。是打印命令,需要指定类型。是print的简写
        p (int)[[[self view] subviews] count]
    2). po 打印对象,会调用对象description方法。是print-object的简写
        po [self view]
    3). expr 可以在调试时动态执行指定表达式,并将结果打印出来。常用于在调试过程中修改变量的值。
    4). bt:打印调用堆栈,是thread backtrace的简写,加all可打印所有thread的堆栈
    5). br l:是breakpoint list的简写
  1. 你一般是怎么用Instruments的?
    Instruments里面工具很多,常用:
    1). Time Profiler: 性能分析
    2). Zombies:检查是否访问了僵尸对象,但是这个工具只能从上往下检查,不智能。
    3). Allocations:用来检查内存,写算法的那批人也用这个来检查。
    4). Leaks:检查内存,看是否有内存泄露。
  1. iOS中常用的数据存储方式有哪些?
数据存储有四种方案:NSUserDefault、KeyChain、file、DB。
    其中File有三种方式:plist、Archive(归档)
    DB包括:SQLite、FMDB、CoreData
  1. iOS的沙盒目录结构是怎样的?
沙盒结构:
1). Application:存放程序源文件,上架前经过数字签名,上架后不可修改。
2). Documents:常用目录,iCloud备份目录,存放数据。(这里不能存缓存文件,否则上架不被通过)
3). Library:
        Caches:存放体积大又不需要备份的数据。(常用的缓存路径)
        Preference:设置目录,iCloud会备份设置信息。
4). tmp:存放临时文件,不会被备份,而且这个文件下的数据有可能随时被清除的可能。
  1. iOS多线程技术有哪几种方式?
答:pthread、NSThread、GCD、NSOperation
  1. GCD 与 NSOperation 的区别:
GCD 和 NSOperation 都是用于实现多线程:
    GCD 基于C语言的底层API,GCD主要与block结合使用,代码简洁高效。
    NSOperation 属于Objective-C类,是基于GCD更高一层的封装。复杂任务一般用NSOperation实现。
  1. 写出使用GCD方式从子线程回到主线程的方法代码
答:dispatch_async(dispatch_get_main_queue(), ^{ });
  1. 如何用GCD同步若干个异步调用?(如根据若干个url异步加载多张图片,然后在都下载完成后合成一张整图)
// 使用Dispatch Group追加block到Global Group Queue,这些block如果全部执行完毕,就会执行Main Dispatch Queue中的结束处理的block。
// 创建队列组
dispatch_group_t group = dispatch_group_create();
// 获取全局并发队列
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
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(栅栏函数)的作用是什么?
函数定义:dispatch_barrier_async(dispatch_queue_t queue, dispatch_block_t block);
作用:
    1.在它前面的任务执行结束后它才执行,它后面的任务要等它执行完成后才会开始执行。
    2.避免数据竞争

 // 1.创建并发队列
 dispatch_queue_t queue = dispatch_queue_create("myQueue", DISPATCH_QUEUE_CONCURRENT);
// 2.向队列中添加任务
dispatch_async(queue, ^{  // 1.2是并行的
    NSLog(@"任务1, %@",[NSThread currentThread]);
});
dispatch_async(queue, ^{
    NSLog(@"任务2, %@",[NSThread currentThread]);
});

 dispatch_barrier_async(queue, ^{
    NSLog(@"任务 barrier, %@", [NSThread currentThread]);
});

 dispatch_async(queue, ^{   // 这两个是同时执行的
    NSLog(@"任务3, %@",[NSThread currentThread]);
});
 dispatch_async(queue, ^{
    NSLog(@"任务4, %@",[NSThread currentThread]);
});

 // 输出结果: 任务1 任务2 ——》 任务 barrier ——》任务3 任务4 
// 其中的任务1与任务2,任务3与任务4 由于是并行处理先后顺序不定。
  1. 以下代码运行结果如何?
  - (void)viewDidLoad {
    [super viewDidLoad];
    NSLog(@"1");
    dispatch_sync(dispatch_get_main_queue(), ^{
        NSLog(@"2");
    });
    NSLog(@"3");
 }
// 只输出:1。(主线程死锁)
  1. 什么是 RunLoop
  从字面上讲就是运行循环,它内部就是do-while循环,在这  个循环内部不断地处理各种任务。
一个线程对应一个RunLoop,基本作用就是保持程序的持续运行,处理app中的各种事件。通过runloop,有事运行,没事就休息,可以节省cpu资源,提高程序性能。

  主线程的run loop默认是启动的。iOS的应用程序里面,程序启动后会有一个如下的main()函数
  int main(int argc, char * argv[]) {
     @autoreleasepool {
         return UIApplicationMain(argc, argv, nil,   NSStringFromClass([AppDelegate class]));
     }
 }
  1. 什么是 Runtime

Runtime又叫运行时,是一套底层的C语言API,其为iOS内部的核心之一,我们平时编写的OC代码,底层都是基于它来实现的。

联系

github地址:https://github.com/meetly
希望大家多多指教!

上一篇下一篇

猜你喜欢

热点阅读