iOS面试题汇总

作者: Devil雅馨 | 来源:发表于2020-12-28 12:55 被阅读0次

    1.简述OC中内存管理机制。与retain配对使用的方法是dealloc还是release,为什么?需要与alloc配对使用的方法是dealloc还是release,为什么?

    OC中内存管理机制应该就是引用计数的增减吧,retainCount为0时释放该内存。
    retain对应的是release,内存的释放用release。
    alloc对应的是dealloc,内存的销毁用dealloc。
    

    2.readwrite,readonly,assign,retain,copy,nonatomic,atomic,strong,weak属性的作用?

    readwrite此标记说明属性会被当成读写的,这也是默认属性。
    readonly此标记说明属性只可以读,也就是不能设置,可以获取。
    assign不会使引用计数加1,也就是直接赋值。
    retain会使引用计数加1。
    copy建立一个索引计数为1的对象,在赋值时使用传入值的一份拷贝。
    nonatomic:非原子性访问,多线程并发访问会提高性能。
    atomic:原子性访问。
    strong:打开ARC时才会使用,相当于retain。
    weak:打开ARC时才会使用,相当于assign,可以把对应的指针变量置为nil。
    

    3.线程是什么?进程是什么?二者有什么区别和联系?

    线程,有时称为轻量级进程,是被系统独立调度和CPU的基本运行单位。
    进程是操作系统中可以并行工作的基本单位。
    一个应用程序里至少有一个进程,一个进程里至少有一个线程。
    

    4.谈谈你对多线程开发的理解?iOS中有几种实现多线程的方法?GCD 与 NSOperation 的区别?

    在一个进程中有多个线程,每个线程有自己单独的任务
    优点效率快   缺点不安全,耗费资源
          第一种,使用@synchronized(self)
          第二种,使用GCD
          第三种,使用NSOperationQueue
    GCD 和 NSOperation 都是用于实现多线程:
        GCD 基于C语言的底层API,GCD主要与block结合使用,代码简洁高效。
        NSOperation 属于Objective-C类,是基于GCD更高一层的封装。复杂任务一般用NSOperation实现。
    

    5.线程同步和异步的区别?IOS中如何实现多线程的同步?

    一个进程启动的多个不相干线程,它们相互之间关系为异步。    
    同步的话指的是多线程同时操作一个数据 这个时候需要对数据添加保护 这个保护就是线程的同步。
    用GCD中的串行队列来解释多线程的同步,也就是队列中的任务为串行,它们各自对相邻的任务有依赖性,如果任务1不完成,那么任务2就不会开始,这就是同步
    

    6.获取一台设备唯一标示的方法有哪些?

    1.UDID
    2.UUID
    3.MAC ADDRESS 
    4.OPEN UDID  
    5.广告标识符         
    6.Vindor标示符
    ios7之后用的时keychain(钥匙串)
    

    7.Objective-C的类可以多重继承么?可以实现多个接口么?Category是什么?重写一个类的方式用继承好还是分类好?为什么?

    Objective-C的类不可以多重继承;可以实现多个接口(协议);
    Category是类别;一般情况用分类好,用Category去重写类的方法,仅对本Category有效,不会影响到其他类与原有类的关系。
    

    8.设计模式是什么? 你知道哪些设计模式,并简要叙述?

    设计模式是一种编码经验,就是用比较成熟的逻辑去处理某一种类型的事情。
    1). MVC模式:Model View Control,把模型 视图 控制器 层进行解耦合编写。
    2). MVVM模式:Model View ViewModel 把模型 视图 业务逻辑 层进行解耦和编写。
    3). 单例模式:通过static关键词,声明全局变量。在整个进程运行期间只会被赋值一次。
    4). 观察者模式:KVO是典型的通知模式,观察某个属性的状态,状态发生变化时通知观察者。
    5). 委托模式:代理+协议的组合。实现1对1的反向传值操作。
    6). 工厂模式:通过一个类方法,批量的根据已有模板生产对象。
    

    9.MVC 和 MVVM 的区别?

    1). MVVM是对胖模型进行的拆分,其本质是给控制器减负,将一些弱业务逻辑放到VM中去处理。
    2). MVC是一切设计的基础,所有新的设计模式都是基于MVC进行的改进。
    

    10.frame 和 bounds 有什么不同?

    frame指的是:该view在父view坐标系统中的位置和大小。(参照点是父view的坐标系统)
    bounds指的是:该view在本身坐标系统中的位置和大小。(参照点是本身坐标系统)
    

    11.堆和栈的区别?

    堆需要用户手动释放内存,而栈则是编译器自动释放内存
    

    12.ios本地数据存储都有哪几种方式?iOS的沙盒目录结构是怎样的?

    数据存储有四种方案:NSUserDefault、KeyChain、file、DB。
    其中File有三种方式:plist、Archive(归档)
    DB包括:SQLite、FMDB、CoreData
    沙盒结构:
    1). Application:存放程序源文件,上架前经过数字签名,上架后不可修改。
    2). Documents:常用目录,iCloud备份目录,存放数据。(这里不能存缓存文件,否则上架不被通过)
    3). Library:
            Caches:存放体积大又不需要备份的数据。(常用的缓存路径)
            Preference:设置目录,iCloud会备份设置信息。
    4). tmp:存放临时文件,不会被备份,而且这个文件下的数据有可能随时被清除的可能。
    

    13.Objective-C 如何对内存管理的,说说你的看法和解决方法?

    Objective-C的内存管理主要有三种方式ARC(自动内存计数)、手动内存计数、内存池。
    1). 自动内存计数ARC:由Xcode自动在App编译阶段,在代码中添加内存管理代码。
    2). 手动内存计数MRC:遵循内存谁申请、谁释放;谁添加,谁释放的原则。
    3). 内存释放池Release Pool:把需要释放的内存统一放在一个池子中,当池子被抽干后(drain),池子中所有的内存空间也被自动释放掉。内存池的释放操作分为自动和手动。自动释放受runloop机制影响。
    

    14.浅拷贝和深拷贝的区别?

    对一个实例进行深拷贝时当前类需要实现NSCopying协议。
    浅拷贝:只复制指向对象的指针,而不复制引用对象本身。
    深拷贝:复制引用对象本身。内存中存在了两份独立对象本身,当修改A时,A_copy不变。
    

    15.什么情况使用 weak 关键字,相比 assign 有什么不同?

    1.在 ARC 中,在有可能出现循环引用的时候,往往要通过让其中一端使用 weak 来解决,比如: delegate 代理属性。
    2.自身已经对它进行一次强引用,没有必要再强引用一次,此时也会使用 weak,自定义 IBOutlet 控件属性一般也使用 weak;当然,也可以使用strong。
    IBOutlet连出来的视图属性为什么可以被设置成weak?
        因为父控件的subViews数组已经对它有一个强引用。
    不同点:
    assign 可以用非 OC 对象,而 weak 必须用于 OC 对象。
    weak 表明该属性定义了一种“非拥有关系”。在属性所指的对象销毁时,属性值会自动清空(nil)。
    

    16.怎么用 copy 关键字?

    用途: 
    1. NSString、NSArray、NSDictionary 等等经常使用copy关键字,是因为他们有对应的可变类型:NSMutableString、NSMutableArray、NSMutableDictionary;
     2. block 也经常使用 copy 关键字。
     说明: block 使用 copy 是从 MRC 遗留下来的“传统”,在 MRC 中,方法内部的 block 是在栈区的,使用 copy 可以把它放到堆区.在 ARC 中写不写都行:对于 block 使用 copy 还是 strong 效果是一样的,但写上 copy 也无伤大雅,还能时刻提醒我们:编译器自动对 block 进行了 copy 操作。如果不写 copy ,该类的调用者有可能会忘记或者根本不知道“编译器会自动对 block 进行了 copy 操作”,他们有可能会在调用之前自行拷贝属性值。这种操作多余而低效。
    

    17.用@property声明的 NSString / NSArray / NSDictionary 经常使用 copy 关键字,为什么?如果改用strong关键字,可能造成什么问题?

    用 @property 声明 NSString、NSArray、NSDictionary 经常使用 copy 关键字,是因为他们有对应的可变类型:NSMutableString、NSMutableArray、NSMutableDictionary,他们之间可能进行赋值操作(就是把可变的赋值给不可变的),为确保对象中的字符串值不会无意间变动,应该在设置新属性值时拷贝一份。
    1. 因为父类指针可以指向子类对象,使用 copy 的目的是为了让本对象的属性不受外界影响,使用 copy 无论给我传入是一个可变对象还是不可对象,我本身持有的就是一个不可变的副本。
    2. 如果我们使用是 strong ,那么这个属性就有可能指向一个可变对象,如果这个可变对象在外部被修改了,那么会影响该属性。
    总结:使用copy的目的是,防止把可变类型的对象赋值给不可变类型的对象时,可变类型对象的值发送变化会无意间篡改不可变类型对象原来的值。
    

    18.常见的 Objective-C 的数据类型有那些,和C的基本数据类型有什么区别?如:NSInteger和int

    Objective-C的数据类型有NSString,NSNumber,NSArray,NSMutableArray,NSData等等,这些都是class,创建后便是对象,而C语言的基本数据类型int,只是一定字节的内存空间,用于存放数值;
    NSInteger是基本数据类型,并不是NSNumber的子类,当然也不是NSObject的子类。
    NSInteger是基本数据类型Int或者Long的别名(NSInteger的定义typedef long NSInteger),它的区别在于,NSInteger会根据系统是32位还是64位来决定是本身是int还是long。
    

    19.id 声明的对象有什么特性?

    id 声明的对象具有运行时的特性,即可以指向任意类型的Objcetive-C的对象。
    

    20.ViewController生命周期

    按照执行顺序排列:
    1. initWithCoder:通过nib文件初始化时触发。
    2. awakeFromNib:nib文件被加载的时候,会发生一个awakeFromNib的消息到nib文件中的每个对象。      
    3. loadView:开始加载视图控制器自带的view。
    4. viewDidLoad:视图控制器的view被加载完成。  
    5. viewWillAppear:视图控制器的view将要显示在window上。
    6. updateViewConstraints:视图控制器的view开始更新AutoLayout约束。
    7. viewWillLayoutSubviews:视图控制器的view将要更新内容视图的位置。
    8. viewDidLayoutSubviews:视图控制器的view已经更新视图的位置。
    9. viewDidAppear:视图控制器的view已经展示到window上。 
    10. viewWillDisappear:视图控制器的view将要从window上消失。
    11. viewDidDisappear:视图控制器的view已经从window上消失。
    

    21.描述应用程序的启动顺序

    1. 程序入口main函数创建UIApplication实例和UIApplication代理实例。
    2. 在UIApplication代理实例中重写启动方法,设置根ViewController。
    3. 在第一ViewController中添加控件,实现应用程序界面。
    

    22.Category(类别)、 Extension(扩展)和继承的区别

    区别:
    1. 分类有名字,类扩展没有分类名字,是一种特殊的分类。
    2. 分类只能扩展方法(属性仅仅是声明,并没真正实现),类扩展可以扩展属性、成员变量和方法。
    3. 继承可以增加,修改或者删除方法,并且可以增加属性。
    

    23.我们说的OC是动态运行时语言是什么意思?

    主要是将数据类型的确定由编译时,推迟到了运行时。简单来说, 运行时机制使我们直到运行时才去决定一个对象的类别,以及调用该类别对象指定方法。
    

    24.为什么很多内置类如UITableViewControl的delegate属性都是assign/week而不是retain/strong?请举例说明。

    避免循环引用    
    比如:对象A创建并引用到了对象B,对象B创建并引用到了对象C,对象C创建并引用到了对象B,这个时候B的引用计数是2,而C的引用计数是1,当A不用B的时候,就释放了B的所有权,这个时候C还引用对象B,所有B不会释放,引用计数为1;因为B也引用着对象C,B不释放,那么C就不会被释放,所有它们的引用计数都为1,并且永远不会被释放,所以形成了循环引用。
    

    25.使用UITableView时候必须要实现的几种方法?

    -(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section;
    -(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath;
    

    26.写一个便利构造器

       MyView *view = [[MyView alloc]initWithName:name andAge:age];
       return [view autorelease];
    }
    

    27.UIImage初始化一张图片有几种方法?简述各自的优缺点。

    3种
    imageNamed:系统会先检查系统缓存中是否有该名字的Image,如果有的话,则直接返回,如果没有,则先加载图像到缓存,然后再返回。
    initWithContentsOfFile:系统不会检查系统缓存,而直接从文件系统中加载并返回。
    imageWithCGImage:scale:orientation 当scale=1的时候图像为原始大小,orientation制定绘制图像的方向。
    

    28.简述你对UIView,UIWindow和CALayer的理解

    UIWindow是应用的窗口
    UIView是创建窗口中的一个视图,可以响应交互事件
    CALayer不可以响应事件
    

    29.什么时候用Delegate(委托模式),什么时候用Notification(通知模式)?

    1). 二者都用于传递消息,不同之处主要在于一个是一对一的,另一个是一对多的。
    2). notification通过维护一个array,实现一对多消息的转发。
    3). delegate需要两者之间必须建立联系,不然没法调用代理的方法;notification不需要两者之间有联系。
    

    30.什么是 KVO 和 KVC?

    1). KVC(Key-Value-Coding):键值编码 是一种通过字符串间接访问对象的方式(即给属性赋值)
        举例说明:
        stu.name = @"张三" // 点语法给属性赋值
        [stu setValue:@"张三" forKey:@"name"]; // 通过字符串使用KVC方式给属性赋值
        stu1.nameLabel.text = @"张三";
        [stu1 setValue:@"张三" forKey:@"nameLabel.text"]; // 跨层赋值
    2). KVO(key-Value-Observing):键值观察机制 他提供了观察某一属性变化的方法,极大的简化了代码。
         KVO只能被KVC触发,包括使用setValue:forKey:方法和点语法。
       // 通过下方方法为属性添加KVO观察
      -(void)addObserver:(NSObject *)observer
                         forKeyPath:(NSString *)keyPath
                         options:(NSKeyValueObservingOptions)options
                         context:(nullable void *)context;
       // 当被观察的属性发送变化时,会自动触发下方方法                   
      -(void)observeValueForKeyPath:(NSString *)keyPath
                                  ofObject:(id)object
                                      change:(NSDictionary *)change
                                     context:(void *)context{}
     KVC 和 KVO 的 keyPath 可以是属性、实例变量、成员变量。
    

    31.KVC的底层实现?

    当一个对象调用setValue方法时,方法内部会做以下操作:
    1). 检查是否存在相应的key的set方法,如果存在,就调用set方法。
    2). 如果set方法不存在,就会查找与key相同名称并且带下划线的成员变量,如果有,则直接给成员变量属性赋值。
    3). 如果没有找到_key,就会查找相同名称的属性key,如果有就直接赋值。
    4). 如果还没有找到,则调用valueForUndefinedKey:和setValue:forUndefinedKey:方法。
    这些方法的默认实现都是抛出异常,我们可以根据需要重写它们。
    

    32.KVO的底层实现?

    KVO基于runtime机制实现。
    

    33.方法和选择器有何不同?

    selector是一个方法的名字,方法是一个组合体,包含了名字和实现。
    

    34.你是否接触过OC中的反射机制?简单聊一下概念和使用

    1). class反射
        通过类名的字符串形式实例化对象。
            Class class = NSClassFromString(@"student"); 
            Student *stu = [[class alloc] init];
        将类名变为字符串。
            Class class =[Student class];
            NSString *className = NSStringFromClass(class);
    2). SEL的反射
        通过方法的字符串形式实例化方法。
            SEL selector = NSSelectorFromString(@"setName");  
            [stu performSelector:selector withObject:@"Mike"];
        将方法变成字符串。
            NSStringFromSelector(@selector*(setName:));
    

    35.调用方法有两种方式:

    1). 直接通过方法名来调用。[person show];
    2). 间接的通过SEL数据来调用 SEL aaa = @selector(show); [person performSelector:aaa];  
    

    36.如何对iOS设备进行性能测试?

    Profile-> Instruments ->Time Profiler
    

    37.开发项目时你是怎么检查内存泄露?

    1). 静态分析 analyze。
    2). instruments工具里面有个leak可以动态分析。
    

    38.什么是懒加载?

    懒加载就是只在用到的时候才去初始化。也可以理解成延时加载。
    我觉得最好也最简单的一个例子就是tableView中图片的加载显示了, 一个延时加载, 避免内存过高,一个异步加载,避免线程堵塞提高用户体验。
    

    39.类变量的 @public,@protected,@private,@package 声明各有什么含义?

    @public 任何地方都能访问;
    @protected 该类和子类中访问,是默认的;
    @private 只能在本类中访问;
    @package 本包内使用,跨包不可以。
    

    40.如何访问并修改一个类的私有属性?

    1). 一种是通过KVC获取。
    2). 通过runtime访问并修改私有属性。
    

    41.什么是block?

    闭包(block):闭包就是获取其它函数局部变量的匿名函数。
    

    42.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");
        }
    }
    

    43.block的注意点

    1). 在block内部使用外部指针且会造成循环引用情况下,需要用__week修饰外部指针:
        __weak typeof(self) weakSelf = self; 
    2). 在block内部如果调用了延时函数还使用弱指针会取不到该指针,因为已经被销毁了,需要在block内部再将弱指针重新强引用一下。
        __strong typeof(self) strongSelf = weakSelf;
    3). 如果需要在block内部改变外部栈区变量的话,需要在用__block修饰外部变量。
    

    44.什么是 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]));
        }
    }
    

    45.什么是 Runtime? Runtime实现的机制是什么,怎么用,一般用于干嘛?

    Runtime又叫运行时,是一套底层的C语言API,其为iOS内部的核心之一,我们平时编写的OC代码,底层都是基于它来实现的。
    1). 使用时需要导入的头文件 <objc/message.h> <objc/runtime.h>
    2). Runtime 运行时机制,它是一套C语言库。
    3). 实际上我们编写的所有OC代码,最终都是转成了runtime库的东西。
        比如:
            类转成了 Runtime 库里面的结构体等数据类型,
            方法转成了 Runtime 库里面的C语言函数,
            平时调方法都是转成了 objc_msgSend 函数(所以说OC有个消息发送机制)
        // OC是动态语言,每个方法在运行时会被动态转为消息发送,即:objc_msgSend(receiver, selector)。
        // [stu show];  在objc动态编译时,会被转意为:objc_msgSend(stu, @selector(show));  
    

    4). 因此,可以说 Runtime 是OC的底层实现,是OC的幕后执行者。
    有了Runtime库,能做什么事情呢?

    Runtime库里面包含了跟类、成员变量、方法相关的API。
    比如:
    (1)获取类里面的所有成员变量。
    (2)为类动态添加成员变量。
    (3)动态改变类的方法实现。
    (4)为类动态添加新的方法等。
    因此,有了Runtime,想怎么改就怎么改。
    

    46.分析json、xml的区别?json、xml解析方式的底层是如何处理的?

    json数据小,易解析,不复杂    xml数据较大,比较复杂
    json中以key/value形式保存,大多数是字典数组模式
    xml中则是<>
    

    47.介绍一下XMPP?

    XMPP是一种以XML为基础的开放式实时通信协议。
    简单的说,XMPP就是一种协议,一种规定。就是说,在网络上传东西,XMM就是规定你上传大小的格式。
    

    48.ViewController的didReceiveMemoryWarning是在什么时候被调用的?默认的操作是什么?

    当应用程序的内存使用接近系统的最大内存使用时,应用会向系统发送内存警告,这时候系统会调用方法向所有的ViewController发送内存警告
    

    49.面向对象的三大特征,并作简单的介绍。

    封装、继承、多态
    封装:将一个实例的所有属性封装到某个类中
    继承:子类继承父类所有方法和属性
    多态:父类指针指向子类对象
    

    50.OC中创建线程的方法是什么?如果在主线程中执行代码,方法是什么?

    // 创建线程的方法
    - [NSThread detachNewThreadSelector:nil toTarget:nil withObject:nil]
    - [self performSelectorInBackground:nil withObject:nil];
    - [[NSThread alloc] initWithTarget:nil selector:nil object:nil];
    - dispatch_async(dispatch_get_global_queue(0, 0), ^{});
    - [[NSOperationQueue new] addOperation:nil];
    
    // 主线程中执行代码的方法
    - [self performSelectorOnMainThread:nil withObject:nil waitUntilDone:YES];
    - dispatch_async(dispatch_get_main_queue(), ^{});
    - [[NSOperationQueue mainQueue] addOperation:nil];
    

    51.tableView的重用机制?

    UITableView 通过重用单元格来达到节省内存的目的: 
    通过为每个单元格指定一个重用标识符,即指定了单元格的种类,当屏幕上的单元格滑出屏幕时,系统会把这个单元格添加到重用队列中,等待被重用,当有新单元格从屏幕外滑入屏幕内时,从重用队列中找看有没有可以重用的单元格,如果有,就拿过来用,如果没有就创建一个来使用。
    

    52.谈谈 UITableView 的优化

    1). 正确的复用cell。
    2). 设计统一规格的Cell
    3). 提前计算并缓存好高度(布局),因为heightForRowAtIndexPath:是调用最频繁的方法;
    4). 异步绘制,遇到复杂界面,遇到性能瓶颈时,可能就是突破口;
    4). 滑动时按需加载,这个在大量图片展示,网络加载的时候很管用!
    5). 减少子视图的层级关系
    6). 尽量使所有的视图不透明化以及做切圆操作。
    7). 不要动态的add 或者 remove 子控件。最好在初始化时就添加完,然后通过hidden来控制是否显示。
    8). 使用调试工具分析问题。
    

    53.如何实行cell的动态的行高

    如果希望每条数据显示自身的行高,必须设置两个属性,1.预估行高,2.自定义行高。
    设置预估行高 tableView.estimatedRowHeight = 200。
    设置定义行高 tableView.estimatedRowHeight = UITableViewAutomaticDimension。 
    如果要让自定义行高有效,必须让容器视图有一个自下而上的约束。
    

    54.如何重写类方法

    1、在子类中实现一个同基类名字一样的静态方法
    2、在调用的时候不要使用类名调用,而是使用[self class]的方式调用。原理,用类名调用是早绑定,在编译期绑定,用[self class]是晚绑定,在运行时决定调用哪个方法。
    

    55.NSNotification和KVO的区别和用法是什么?什么时候应该使用通知,什么时候应该使用KVO,它们的实现上有什么区别吗?如果用protocol和delegate(或者delegate的Array)来实现类似的功能可能吗?如果可能,会有什么潜在的问题?如果不能,为什么?(虽然protocol和delegate这种东西面试已经面烂了…)

    NSNotification是通知模式在iOS的实现,KVO的全称是键值观察
    (Key-value observing),其是基于KVC(key-value coding)的,KVC是一
    个通过属性名访问属性变量的机制。例如将Module层的变化,通知到多
    个Controller对象时,可以使用NSNotification;如果是只需要观察某个
    对象的某个属性,可以使用KVO。
    对于委托模式,在设计模式中是对象适配器模式,其是delegate是指向
    某个对象的,这是一对一的关系,而在通知模式中,往往是一对多的关
    系。委托模式,从技术上可以现在改变delegate指向的对象,但不建议
    这样做,会让人迷惑,如果一个delegate对象不断改变,指向不同的对
    象。
    

    56.你用过NSOperationQueue么?如果用过或者了解的话,你为什么要使用NSOperationQueue,实现了什么?请描述它和G.C.D的区别和类似的地方(提示:可以从两者的实现机制和适用范围来描述)。

    使用NSOperationQueue用来管理子类化的NSOperation对象,控制
    其线程并发数目。GCD和NSOperation都可以实现对线程的管理,区别
    是 NSOperation和NSOperationQueue是多线程的面向对象抽象。项目中
    使用NSOperation的优点是NSOperation是对线程的高度抽象,在项目中
    使用它,会使项目的程序结构更好,子类化NSOperation的设计思路,
    是具有面向对象的优点(复用、封装),使得实现是多线程支持,而接
    口简单,建议在复杂项目中使用。
    项目中使用GCD的优点是GCD本身非常简单、易用,对于不复杂的多线
    程操作,会节省代码量,而Block参数的使用,会是代码更为易读,建议
    在简单项目中使用。
    

    57.既然提到G.C.D,那么问一下在使用G.C.D以及block时要注意些什么?它们两是一回事儿么?block在ARC中和传统的MRC中的行为和用法有没有什么区别,需要注意些什么?

    使用block是要注意,若将block做函数参数时,需要把它放到最
    后,GCD是Grand Central Dispatch,是一个对线程开源类库,而Block
    是闭包,是能够读取其他函数内部变量的函数。
    

    58.对于Objective-C,你认为它最大的优点和最大的不足是什么?对于不足之处,现在有没有可用的方法绕过这些不足来实现需求。如果可以的话,你有没有考虑或者实践过重新实现OC的一些功能,如果有,具体会如何做?

    最大的优点是它的运行时特性,不足是没有命名空间,对于命名冲
     突,可以使用长命名法或特殊前缀解决,如果是引入的第三方库之间的
    命名冲突,可以使用link命令及flag解决冲突。
    

    59.OC和swift的区别

    1)快速、现代、安全、互动,而且明显优于 Objective-C 语言;
    2)可以使用现有的 Cocoa 和 Cocoa Touch 框架;
    3)Swift 取消了 Objective-C 的指针/地址等不安全访问的使用;
    4)提供了类似 Java 的名字空间(namespace)、泛型(generic)var、运算对象重载(operator overloading);
    5)Swift 被简单的形容为 “没有 C 的 Objective-C”(Objective-C without the C);
    6)为苹果开发工具带来了 Xcode Playgrounds 功能,该功能提供强大的互动效果,能让 Swift 源代码在撰写过程中实时显示出其运行结果;
    7)基于 C 和 Objective-C,而却没有C的一些兼容约束;
    8)采用了安全的编程模式;
    9)界面基于 Cocoa 和 Cocoa Touch 框架;
    10)舍弃 Objective C 早期应用 Smalltalk 的语法,保留了 Smalltalk 的动态特性,全面改为句点表示法;
    11)类型严谨对比 Objective-C 的动态绑定。
    

    60.描述下SDWebImage里面给UIImageView加载图片的逻辑

    SDWebImage 中为 UIImageView 提供了一个分类UIImageView+WebCache.h, 这个分类中有一个最常用的接口sd_setImageWithURL:placeholderImage:,会在真实图片出现前会先显示占位图片,当真实图片被加载出来后再替换占位图片。
    加载图片的过程大致如下:
        1.首先会在 SDWebImageCache 中寻找图片是否有对应的缓存, 它会以url 作为数据的索引先在内存中寻找是否有对应的缓存
        2.如果缓存未找到就会利用通过MD5处理过的key来继续在磁盘中查询对应的数据, 如果找到了, 就会把磁盘中的数据加载到内存中,并将图片显示出来
        3.如果在内存和磁盘缓存中都没有找到,就会向远程服务器发送请求,开始下载图片
        4.下载后的图片会加入缓存中,并写入磁盘中
        5.整个获取图片的过程都是在子线程中执行,获取到图片后回到主线程将图片显示出来
    SDWebImage原理:
    调用类别的方法:
        1. 从内存(字典)中找图片(当这个图片在本次使用程序的过程中已经被加载过),找到直接使用。
        2. 从沙盒中找(当这个图片在之前使用程序的过程中被加载过),找到使用,缓存到内存中。
        3. 从网络上获取,使用,缓存到内存,缓存到沙盒。
    

    相关文章

      网友评论

        本文标题:iOS面试题汇总

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