整理一篇很全面的iOS面试题

本文详细梳理了iOS开发中的面试重点,包括基础知识点、第三方框架、算法、编码格式优化和其它知识点。重点讨论了Objective-C中的属性、内存管理、线程、数据结构与算法、多线程、Block、Category、KVO与KVC、网络请求等,同时也涉及了面试中常见的数据存储方式、性能优化和框架设计。文中深入探讨了各种技术的原理、使用场景和最佳实践,是iOS开发者面试准备的重要参考资料。
摘要由CSDN通过智能技术生成

(答案不唯一,仅供参考,文章最后有福利)
目录

一、基础知识点
二、第三方框架
三、算法
四、编码格式(优化细节)
五、其他知识点

一、基础知识点

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

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

  2. MVC 和 MVVM 的区别

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

  3. #import跟 #include 有什么区别,@class呢,#import<> 跟 #import””有什么区别?

    1). #import是Objective-C导入头文件的关键字,#include是C/C++导入头文件的关键字,使用#import头文件会自动只导入一次,不会重复导入。
    2). @class告诉编译器某个类的声明,当执行时,才去查看类的实现文件,可以解决头文件的相互包含。
    3). #import<>用来包含系统的头文件,#import””用来包含用户头文件。

  4. frame 和 bounds 有什么不同?

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

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

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

  6. @property 的本质是什么?ivar、getter、setter 是如何生成并添加到这个类中的

    @property 的本质是什么?
    @property = ivar + getter + setter;
    “属性” (property)有两大概念:ivar(实例变量)、getter+setter(存取方法)
    “属性” (property)作为 Objective-C 的一项特性,主要的作用就在于封装对象中的数据。 Objective-C 对象通常会把其所需要的数据保存为各种实例变量。实例变量一般通过“存取方法”(access method)来访问。其中,“获取方法” (getter)用于读取变量值,而“设置方法” (setter)用于写入变量值。

  7. @property中有哪些属性关键字?/ @property 后面可以有哪些修饰符?

    属性可以拥有的特质分为四类:
    1.原子性— nonatomic 特质
    2.读/写权限—readwrite(读写)、readonly (只读)
    3.内存管理语义—assign、strong、 weak、unsafe_unretained、copy
    4.方法名—getter= 、setter=
    5.不常用的:nonnull,null_resettable,nullable

  8. 属性关键字 readwrite,readonly,assign,retain,copy,nonatomic 各是什么作用,在那种情况下用?

    1). readwrite 是可读可写特性。需要生成getter方法和setter方法。
    2). readonly 是只读特性。只会生成getter方法,不会生成setter方法,不希望属性在类外改变。
    3). assign 是赋值特性。setter方法将传入参数赋值给实例变量;仅设置变量时,assign用于基本数据类型。
    4). retain(MRC)/strong(ARC) 表示持有特性。setter方法将传入参数先保留,再赋值,传入参数的retaincount会+1。
    5). copy 表示拷贝特性。setter方法将传入对象复制一份,需要完全一份新的变量时。
    6). nonatomic 非原子操作。不写的话默认就是atomic。atomic 和 nonatomic 的区别在于,系统自动生成的 getter/setter 方法不一样。对于atomic的属性,系统生成的 getter/setter 会保证 get、set 操作的完整性,而nonatomic就没有这个保证了。所以,nonatomic的速度要比atomic快。
    不过atomic可并不能保证线程安全。
    参考:[爆栈热门 iOS 问题] atomic 和 nonatomic 有什么区别?

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

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

  10. 怎么用 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 操作”,他们有可能会在调用之前自行拷贝属性值。这种操作多余而低效。
  1. 用@property声明的 NSString / NSArray / NSDictionary 经常使用 copy 关键字,为什么?如果改用strong关键字,可能造成什么问题?

    答:用 @property 声明 NSString、NSArray、NSDictionary 经常使用 copy 关键字,是因为他们有对应的可变类型:NSMutableString、NSMutableArray、NSMutableDictionary,他们之间可能进行赋值操作(就是把可变的赋值给不可变的),为确保对象中的字符串值不会无意间变动,应该在设置新属性值时拷贝一份。

>  
> 1\. 因为父类指针可以指向子类对象,使用 copy 的目的是为了让本对象的属性不受外界影响,使用 copy 无论给我传入是一个可变对象还是不可对象,我本身持有的就是一个不可变的副本。
> 2\. 如果我们使用是 strong ,那么这个属性就有可能指向一个可变对象,如果这个可变对象在外部被修改了,那么会影响该属性。
>  
> 总结:使用copy的目的是,防止把可变类型的对象赋值给不可变类型的对象时,可变类型对象的值发送变化会无意间篡改不可变类型对象原来的值。
  1. 浅拷贝和深拷贝的区别?

    浅拷贝:只复制指向对象的指针,而不复制引用对象本身。

> 深拷贝:复制引用对象本身。内存中存在了两份独立对象本身,当修改A时,A_copy不变。
  1. 系统对象的 copy 与 mutableCopy 方法

    不管是集合类对象(NSArray、NSDictionary、NSSet … 之类的对象),还是非集合类对象(NSString, NSNumber … 之类的对象),接收到copy和mutableCopy消息时,都遵循以下准则:

> 1\. copy 返回的是不可变对象(immutableObject);如果用copy返回值调用mutable对象的方法就会crash。
> 2\. mutableCopy 返回的是可变对象(mutableObject)。
一、非集合类对象的copy与mutableCopy
      在非集合类对象中,对不可变对象进行copy操作,是指针复制,mutableCopy操作是内容复制;
      对可变对象进行copy和mutableCopy都是内容复制。用代码简单表示如下: NSString *str = @"hello word!"; NSString *strCopy = [str copy] // 指针复制,strCopy与str的地址一样 NSMutableString *strMCopy = [str mutableCopy] // 内容复制,strMCopy与str的地址不一样   NSMutableString *mutableStr = [NSMutableString stringWithString: @"hello word!"]; NSString *strCopy = [mutableStr copy] // 内容复制 NSMutableString *strMCopy = [mutableStr mutableCopy] // 内容复制
二、集合类对象的copy与mutableCopy (同上)
      在集合类对象中,对不可变对象进行copy操作,是指针复制,mutableCopy操作是内容复制;
      对可变对象进行copy和mutableCopy都是内容复制。但是:集合对象的内容复制仅限于对象本身,对集合内的对象元素仍然是指针复制。(即单层内容复制) NSArray *arr = @[@[@"a", @"b"], @[@"c", @"d"]; NSArray *copyArr = [arr copy]; // 指针复制 NSMutableArray *mCopyArr = [arr mutableCopy]; //单层内容复制 NSMutableArray *array = [NSMutableArray arrayWithObjects:[NSMutableString stringWithString:@"a"],@"b",@"c",nil]; NSArray *copyArr = [mutableArr copy]; // 单层内容复制 NSMutableArray *mCopyArr = [mutableArr mutableCopy]; // 单层内容复制

【总结一句话】:
只有对不可变对象进行copy操作是指针复制(浅复制),其它情况都是内容复制(深复制)!

  1. *这个写法会出什么问题:@property (nonatomic, copy) NSMutableArray arr;

    问题:添加,删除,修改数组内的元素的时候,程序会因为找不到对应的方法而崩溃。
    //如:-[__NSArrayI removeObjectAtIndex:]: unrecognized selector sent to instance 0x7fcd1bc30460
    // copy后返回的是不可变对象(即 arr 是 NSArray 类型,NSArray 类型对象不能调用 NSMutableArray 类型对象的方法)
    原因:是因为 copy 就是复制一个不可变 NSArray 的对象,不能对 NSArray 对象进行添加/修改。

  2. 如何让自己的类用 copy 修饰符?如何重写带 copy 关键字的 setter?

    若想令自己所写的对象具有拷贝功能,则需实现 NSCopying 协议。如果自定义的对象分为可变版本与不可变版本,那么就要同时实现 NSCopying 与 NSMutableCopying 协议。
    具体步骤:
    1. 需声明该类遵从 NSCopying 协议
    2. 实现 NSCopying 协议的方法。
    // 该协议只有一个方法:

    • (id)copyWithZone:(NSZone *)zone;
      // 注意:使用 copy 修饰符,调用的是copy方法,其实真正需要实现的是 “copyWithZone” 方法。
  3. **写一个 setter 方法用于完成 @property (nonatomic, retain) NSString name,写一个 setter 方法用于完成 @property (nonatomic, copy) NSString name

// retain - (void)setName:(NSString *)str {
      [str retain];
      [_name release];
      _name = str;
    } // copy - (void)setName:(NSString *)str {
      id t = [str copy];
      [_name release];
      _name = t;
    }
  1. @synthesize 和 @dynamic 分别有什么作用?

    @property有两个对应的词,一个是@synthesize(合成实例变量),一个是@dynamic。
    如果@synthesize和@dynamic都没有写,那么默认的就是 @synthesize var = _var;
    // 在类的实现代码里通过 @synthesize 语法可以来指定实例变量的名字。(@synthesize var = _newVar;)
    1. @synthesize 的语义是如果你没有手动实现setter方法和getter方法,那么编译器会自动为你加上这两个方法。
    2. @dynamic 告诉编译器,属性的setter与getter方法由用户自己实现,不自动生成(如,@dynamic var)。

  2. 常见的 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。

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

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

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

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

  5. Objective-C 中创建线程的方法是什么?如果在主线程中执行代码,方法是什么?如果想延时执行代码、方法又是什么?

    答:线程创建有三种方法:使用NSThread创建、使用GCD的dispatch、使用子类化的NSOperation,然后将其加入NSOperationQueue;在主线程执行代码,方法是performSelectorOnMainThread,如果想延时执行代码可以用performSelector:onThread:withObject:waitUntilDone:

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

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

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

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

  8. 为什么我们常见的delegate属性都用是week而不是retain/strong?

    答:是为了防止delegate两端产生不必要的循环引用。
    @property (nonatomic, weak) id delegate;

  9. 什么时候用delete,什么时候用Notification?

    Delegate(委托模式):1对1的反向消息通知功能。
    Notification(通知模式):只想要把消息发送出去,告知某些状态的变化。但是并不关心谁想要知道这个。

  10. 什么是 KVO 和 KVC?

    1). KVC(Key-Value-Coding):键值编码 是一种通过字符串间接访问对象的方式(即给属性赋值)

> 举例说明:
> [stu.name](https://link.jianshu.com/?t=http%3A%2F%2Fstu.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 co
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值