2018年五月份面试整理

先扯点废话,五月份面试的不多,就面试一周哈,差不多面试了五六家的样子,拿了两个offer(其中一个是技术过了,因为模式的问题本人直接拒接了),当然也拿到一个满意的offer了。面试题整理一些是自己碰到的,一些是百度上的,个人觉得可以算上是复习一下,也顺便整理进来了。

1、OC的面向对象

面向对象:封装、继承、多态。
ps:被问懵过(第一个想法就是OC中不都是面向对象开发吗?对象不就是创建一个嘛...特么有毒),想想就觉得没脸见人...初学者都会的东西,做了几年开发后竟然回答不上来。

什么是多态

一个方法,不同的实现,主要体现:重写以及方法重载,OC中没有严格的方法重载。

2、block和 weak修饰符的区别?

__block不管是 ARC 还是MRC模式下都可以使用,可以修饰对象,也可以修饰基本数据类型;
__weak只能在 ARC 模式下使用,只能修饰对象(NSString),不能修饰基本数据类型;
__block修饰的对象可以在block中被重新赋值,中被重新赋值,__weak修饰的对象不可以。
归结
__weak只能修饰对象,在block中不可被修改,可用于解决block的循环引用
__block既可以修饰对象也可以修饰基本数据类型,主要用于修饰在block外部创建的变量,可以在block里面进行修改变量

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

weak的使用情况

  • 在 ARC 中,在有可能出现循环引用的时候,往往要通过让其中一端使用 weak 来解决,比如:delegate 代理属性,代理属性也可使用 assign
  • 自身已经对它进行一次强引用,没有必要再强引用一次,此时也会使用 weak,自定义
  • IBOutlet 控件属性一般也使用 weak;当然,也可以使用 strong,但是建议使用 weak,(可以加深问为什么建议使用weak,顺手百度科普一下)。
    assign:
    一般都是用来修饰基本数据类型非 OC 对象,比如:int、bool等。
    weak 和 assign 的不同点:
    weak 策略在属性所指的对象遭到摧毁时,系统会将 weak 修饰的属性对象的指针指向 nil,在 OC 给 nil 发消息是不会有什么问题的;如果使用 assign 策略在属性所指的对象遭到摧毁时,属性对象指针还指向原来的对象,由于对象已经被销毁,这时候就产生了野指针,如果这时候在给此对象发送消息,很容造成程序奔溃。
    assigin 可以用于修饰非 OC 对象,而 weak 必须用于 OC 对象。
4、category 和 extension 的区别
  • 分类有名字,类扩展没有分类名字,是一种特殊的分类
  • 分类只能扩展方法(属性仅仅是声明,并没真正实现),类扩展可以扩展属性、成员变量和方法。
5、define 和 const常量有什么区别?
  • define 在预处理阶段进行替换,const 常量在编译阶段使用
  • 宏不做类型检查,仅仅进行替换,const 常量有数据类型,会执行类型检查
  • define 不能调试,const 常量可以调试
  • define 定义的常量在替换后运行过程中会不断地占用内存,而 const 定义的常量存储在数据段只有一份 copy,效率更高
  • define 可以定义一些简单的函数,const 不可以;当然可以用inline替换define定义函数。
6、static关键字的作用
  • 函数(方法)体内 static 变量的作用范围为该函数体,该变量的内存只被分配一次,因此其值在下次调用时仍维持上次的值;
  • 在模块内的 static 全局变量可以被模块内所用函数访问,但不能被模块外其它函数访问;
  • 在模块内的 static 函数只可被这一模块内的其它函数调用,这个函数的使用范围被限制在声明 它的模块内;
  • 在类中的 static 成员变量属于整个类所拥有,对类的所有对象只有一份拷贝;
  • 在类中的 static 成员函数属于整个类所拥有,这个函数不接收 this 指针,因而只能访问类的 static 成员变量。
7、Objective-C使用什么机制管理对象内存?
  • MRC 手动引用计数
  • ARC 自动引用计数,现在通常 ARC
    通过 retainCount 的机制来决定对象是否需要释放。 每次 runloop 的时候,都会检查对象的 retainCount,如果 retainCount 为 0,说明该对象没有地方需要继续使用了,可以释放掉了。
8、ARC下还会存在内存泄露吗?

循环引用会导致内存泄露.
Objective-C 对象与 CoreFoundation 对象进行桥接的时候如果管理不当也会造成内存泄露.
CoreFoundation 中的对象不受 ARC 管理,需要开发者手动释放。

9、常用什么设计模式,如何使用?

常用几种设计模式比如:工厂模式、单例模式、观察者模式等等。

10、KVO原理
  • KVO 是基于 runtime 机制实现的。
  • 当某个类的属性对象第一次被观察时,系统就会在运行期动态地创建该类的一个派生类,在这个派生类中重写基类中任何被观察属性的 setter 方法。派生类在被重写的 setter 方法内实现真正的通知机制。
    如果原类为 Person,那么生成的派生类名为NSKVONotifying_Person每个类对象中都有一个 isa 指针指向当前类,当一个类对象的第一次被观察,那么系统会偷偷将 isa 指针指向动态生成的派生类,从而在给被监控属性赋值时执行的是派生类的 setter 方法键值观察通知依赖于NSObject的两个方法 : willChangeValueForKey: 和 didChangevlueForKey:;在一个被观察属性发生改变之前, willChangeValueForKey:一定会被调用,这就 会记录旧的值。而当改变发生后,didChangeValueForKey: 会被调用,继而 observeValueForKey:ofObject:change:context: 也会被调用。
  • 补充:KVO 的这套实现机制中苹果还偷偷重写了 class 方法,让我们误认为还是使用的当前类 ,从而达到隐藏生成的派生类。

如何手动触发一个 value的 KVO
自动触发的场景:在注册 KVO 之前设置一个初始值,注册之后,设置一个不一样的值,就可以触发了。
想知道如何手动触发,必须知道自动触发 KVO 的原理,见上面的描述手动触发演示。

@property (nonatomic, strong) NSDate *now;

- (void)viewDidLoad
{
[super viewDidLoad];

// “手动触发 self.now的 KVO”,必写。
[self willChangeValueForKey:@"now"];

// “手动触发 self.now的 KVO”,必写。
[self didChangeValueForKey:@"now"];
}
11、UIView和CALayer是什么关系?

UIView显示在屏幕上归功于CALayer,通过调用drawRect方法来渲染自身的内容,调节CALayer属性可以调整UIView的外观,UIView继承自UlResponder,比起CALayer可以响应用户事件,Xcode 6之后可以方便的通过视图调试功能查看图层之间的关系。
UIView是iOS系统中界面元素的基础,所有的界面元素都继承自它。它内部是由Core Animation来实现的,它真正的绘图部分是由一个叫CALayer(Core AnimationLayer)的类来管理。UlView 本身更像是一个CALayer的管理器,访问它的绘图和坐标有关的属性,如frame, bounds 等,实际上内部都是访问它所在CALayer的相关属性。
UIView有个layer属性,可以返回它的主CALayer实例, UlView有一个layerClass方法,返回layer所有使用的类,UIView的子类,可以通过重载这个方法,来让UIView使用不同的CALayer来显示。

12、OC的反射机制
  • class反射:􏲫􏳽􏰘􏰳􏰁􏱡􏴍􏴎􏴏􏰟􏳓􏲗􏰈􏱌􏱸􏲧通过类名字符串形式实例化对象。
Class class = NSClassFromString(@"student");
Student *stu = [ [class alloc] init];
  • SEL反射:通过方法的字符串形式实例化方法。
SEL selector = NSSelectorFromString(@"setName");
[stu performSelector:selector withObject:@"Mike"];
// 将方法变成字符串
NSStringFromSelector(@selector*(setName:));
13、KVC和 KVO的 keyPath一定是属性么?

不一定,可以是成员变量。

14、@synthesize 和 @dynamic分别有什么作用?

@property 有两个对应的词,一个是 @synthesize ,一个是@dynamic。如果 @synthesize 和@dynamic 都没写,那么默认的就是@syntheszie var = _var;

  • @synthesize 的语义是如果你没有手动实现 setter 方法和 getter 方法,那么编译器会自动为你加上这两个方法
  • @dynamic 告诉编译器:属性的 setter 与 getter 方法由用户自己实现,不自动生成(当然对于 readonly 的属性只需提供 getter 即可)
    假如一个属性被声明为@dynamic var,然后你没有提供@setter 方法和@getter 方法,编译的时候没问题,但是当程序运行到instance.var = someVar,由于缺 setter方法会导致程序崩溃;或者当运行到 someVar = instance.var 时,由于缺 getter 方法同样会导致崩溃。编译时没问题,运行时才执行相应的方法,这就是所谓的动态绑定。
15、@synthesize合成实例变量的规则是什么?假如 property名为 foo,存在一个名为_foo的实例变量,那么还会自动合成新变量么?

先回答第二个问题:不会
@synthesize 合成成员变量的规则,有以下几点:
如果指定了成员变量的名称,会生成一个指定的名称的成员变量
如果这个成员已经存在了就不再生成了
如果指定@synthesize foo;就会生成一个名称为 foo 的成员变量,也就是说:会自动生成一个属性同名的成员变量 @interfaceXMGPerson:NSObject
@property (nonatomic, assign) int age;
@end
@implementation XMGPerson
// 不加这语句默认生成的成员变量名为_age
// 如果加上这一句就会生成一个跟属性名同名的成员变量
@synthesize age;
@end
如果是 @synthesize foo = _foo; 就不会生成成员变量了。

16、在有了自动合成属性实例变量之后 ,@synthesize还有哪些使用场景?

不会 autosynthesis(自动合成):

  • 同时重写了 setter 和 getter 时
  • 重写了只读属性的 getter 时
  • 使用了@dynamic 时
  • 在 @protocol 中定义的所有属性
  • 在 category 中定义的所有属性
  • 重载的属性,当你在子类中重载了父类中的属性,必须使用@synthesize 来手动合成 ivar

应用场景:
当你同时重写了 setter 和 getter 时,系统就不会生成 ivar)。这时候有两种选择:
1.手动创建 ivar
2.使用@synthesize foo = _foo;,关联@property 与 ivar
可以用来修改成员变量名,一般不建议这么做,建议使用系统自动生成的成员变量

17、ivar、getter、setter是如何生成并添加到这个类中的?

使用“自动合成”( autosynthesis)
这个过程由编译器在编译阶段执行自动合成,所以编辑器里看不到这些“合成方法”(synthesized method)的源代码
除了生成 getter、setter 方法之外,编译器还要自动向类中添加成员变量(在属性名前面加下划线,以此作为实例变量的名字)
为了搞清属性是怎么实现的,反编译相关的代码,他大致生成了五个东西
// 该属性的“偏移量” (offset),这个偏移量是“硬编码” (hardcode),表示该变量距离存放对象的内存区域的起始地址有多远
OBJC_IVAR_类名属性名称

// 方法对应的实现函数
setter与 getter

// 成员变量列表
ivar_list

// 方法列表
method_list

// 属性列表
prop_list

每次增加一个属性,系统都会在 ivar_list 中添加一个成员变量的描述
在 method_list 中增加 setter 与 getter 方法的描述
在 prop_list 中增加一个属性的描述
计算该属性在对象中的偏移量
然后给出 setter 与 getter 方法对应的实现,在 setter 方法中从偏移量的位置开始赋值,在 getter 方法中从偏移量开始取值,为了能够读取正确字节数,系统对象偏移量的指针类型进行了类型强转。

18、怎么用 copy 关键字?

NSString、NSArray、NSDictionary 等等经常使用 copy 关键字,是因为他们有对应的可变类型:NSMutableString、NSMutableArray、NSMutableDictionary,为确保对象中的属性值不会无意间变动,应该在设置新属性值时拷贝一份,保护其封装性
block 也经常使用 copy 关键字
block 使用 copy 是从 MRC 遗留下来的“传统”,在 MRC 中,方法内部的block 是在栈区的,使用 copy 可以把它放到堆区.
在 ARC 中写不写都行:对于 block 使用 copy 还是 strong 效果是一样的,但是建议写上 copy,因为这样显示告知调用者“编译器会自动对 block 进行了 copy 操作”

19、用@property声明的 NSString(或 NSArray,NSDictionary)经常使用 copy关键字,为什么?如果改用 strong关键字,可能造成什么问题?

因为父类指针可以指向子类对象,使用 copy 的目的是为了让本对象的属性不受外界影响,使用 copy 无论给我传入是一个可变对象还是不可对象,我本身持有的就是一个不可变的副本.如果我们使用是 strong,那么这个属性就有可能指向一个可变对象,如果这个可变对象在外部被修改了,那么会影响该属性.
复制详解:

  • 浅复制(shallow copy):在浅复制操作时,对于被复制对象的每一层都是指针复制。
  • 深复制(one-level-deepcopy):在深复制操作时,对于被复制对象,至少有一层是深复制。
  • 完全复制(real-deepcopy):在完全复制操作时,对于被复制对象的每一层都是对象复制。

非集合类对象的 copy 与 mutableCopy

  • [不可变对象 copy] // 浅复制
  • [不可变对象 mutableCopy] //深复制
  • [可变对象 copy] //深复制
  • [可变对象 mutableCopy] //深复制

集合类对象的 copy 与 mutableCopy

  • [不可变对象 copy] // 浅复制
  • [不可变对象 mutableCopy] //单层深复制
  • [可变对象 copy] //单层深复制
  • [可变对象 mutableCopy] //单层深复制

这里需要注意的是集合对象的内容复制仅限于对象本身,对象元素仍然是指针复制。

20、如何让自定义类可以用 copy 修饰符?如何重写带 copy 关键字的 setter?

若想令自己所写的对象具有拷贝功能,则需实现 NSCopying 协议。如果自定义的对象分为可变版本与不可变版本 , 那么就要同时实现 NSCopyiog 与NSMutableCopying 协议,不过一般没什么必要,实现 NSCopying 协议就够了。

// 实现不可变版本拷贝
- (id)copyWithZone:(NSZone *)zone;
// 实现可变版本拷贝
- (id)mutableCopyWithZone:(NSZone *)zone;
// 重写带 copy 关键字的 setter
- (void)setName:(NSString *)name
{
    _name = [name copy];
}
21、@property后面可以有哪些修饰符?
  • 原子性---nonatomic 特质,如果不写默认情况为 atomic(系统会自动加上同步锁,影响性能)在 iOS 开发中尽量指定为 nonatomic,这样有助于提高程序的性能
  • 读/写权限---readwrite(读写)、readooly (只读)
  • 内存管理语义---assign、strong、 weak、unsafe_unretained、copy
  • 方法名---getter=、setter=
    @property (nonatomic, getter=isOn) BOOL on;
    // setter=<name>这种不常用,也不推荐使用。故不在这里给出
    写法
  • 不常用的:nonnull,null_resettable,nullable
22、使用 atomic一定是线程安全的吗?

不是,atomic 的本意是指属性的存取方法是线程安全的,并不保证整个对象是线程安全的。
举例:声明一个 NSMutableArray 的原子属性 stuff,此时 self.stuff 和 self.stuff = othersulf 都是线程安全的。但是,使用[self.stuffobjectAtIndex:index]就不是线程安全的,需要用互斥锁来保证线程安全性

23、@protocol 和 category 中如何使用

@property
在 protocol 中使用 property 只会生成 setter 和 getter 方法声明,我们使用属性的目的,是希望遵守我协议的对象能实现该属性
category 使用 @property 也是只会生成 setter 和 getter 方法声明,如果我们真的需要给 category 增加属性的实现,需要借助于运行时的两个函数:

  • objc_setAssociatedObject
  • objc_getAssociatedObject

PS:这边可以去了解一下runtime

24、+(void)load; +(void)initialize;有什么用处?

+(void)load;
当类对象被引入项目时, runtime 会向每一个类对象发送 load 消息。
load 方法会在每一个类甚至分类被引入时仅调用一次,调用的顺序:父类优先于子类, 子类优先于分类。
由于 load 方法会在类被 import 时调用一次,而这时往往是改变类的行为的最佳时机,在这里可以使用例如 method swizlling 来修改原有的方法。
load 方法不会被类自动继承。
+(void)initialize;
也是在第一次使用这个类的时候会调用这个方法,也就是说 initialize 也是懒加载
总结:
在 Objective-C 中,runtime 会自动调用每个类的这两个方法:

  • +load 会在类初始加载时调用
  • +initialize 会在第一次调用类的类方法或实例方法之前被调用
    这两个方法是可选的,且只有在实现了它们时才会被调用

两者的共同点:两个方法都只会被调用一次。

25、id 与instancetype
  • id可以当返回值类型并且可以声明对象
  • instancetype只可以当返回值类型
  • instancetype 返回和方法所在类相同类型的对象,id返回未知类型的对象(instancetype会对返回值类型做一个检查,检查你这个返回值是否为当前类的类型)。
  • 自定义初始化方法,返回值类型如果写成id,编译器会自动转成instancetype。
26、Foundation对象与 Core Foundation对象有什么区别

Foundation 框架是使用 OC 实现的,Core Foundation 是使用 C 实现的。
Foundation 对象 和 Core Foundation 对象间的转换:俗称桥接
ARC 环境桥接关键字:

    // 可用于 Foundation对象 和 Core Foundation对象间的转换
    __bridge

    // 用于Foundation对象 转成 Core Foundation对象
    __bridge_retained

    // Core Foundation对象 转成 Foundation对象
    __bridge_transfer
__bridge

如果使用__bridge桥接,它仅仅是将 strOC 的地址给了 strC, 并没有转移对象的所有权,也就是说, 如果使用__bridge 桥接, 那么如果 strOC 释放了,strC 也不能用了。

NSString *strOC1 = [NSString stringWithFormat:@"abcdefg"];
CFStringRef strC1 = (__bridge CFStringRef)strOC1;
NSLog(@"%@ %@", strOC1, strC1);
__bridge_retained

如果使用__bridge_retained 桥接,它会将对象的所有权转移给 strC, 也就是说, 即便 strOC被释放了, strC也可以使用。
注意:在 ARC 条件下,如果是使用__bridge_retained 桥接,那么 strC 必须自己手动释放,因为桥接的时候已经将对象的所有权转移给了 strC,而 C 语言的东西不是不归ARC 管理的 。

NSString*strOC2=[NSStringstringWithFormat:@"abcdefg"];
//  CFStringRef strC2   =   (__bridge_retained
CFStringRef)strOC2;
CFStringRef strC2 = CFBridgingRetain(strOC2);// 这一句, 就
等同于上一句
CFRelease(strC2);
__bridge_transfer

如果使用__bridge_transfer 桥接,它会将对象的所有权转移给 strOC, 也就是说, 即便 strC被释放了, strOC也可以使用 。
如果使用__bridge_transfer 桥接, 他会自动释放 strC, 也就是以后我们不用手动释放 strC。

CFStringRef  strC4  =
CFStringCreateWithCString(CFAllocatorGetDefault(),
"12345678", kCFStringEncodingASCII);
//  NSString *strOC = (__bridge_transfer NSString
*)strC;
NSString *strOC4 = CFBridgingRelease(strC4); // 这一句, 就
等同于上一句
27、runloop和线程有什么关系?

runloop,正如其名,loop表示循环,和run放在一起就表示一直在运行着的循环。实际上,runloop和线程是紧密相连的,可以这么说runloop是为了线程而生,没有线程,runloop就没有存在的必要。runloop是线程的基础架构部分,Cocoa和CoreFundation都提供了runloop对象方便配置和管理线程的runloop。
具体的可以参考这篇博客

28、runloop的mode作用

model主要是用来指定事件在runloop中的优先级:

  • NSDefaultRunLoopMode:默认,空闲状态
  • UITrackingRunLoopMode:不受手指滑动的限制而停止,例如scrollView滑动时不会停止
  • NSRunLoopCommonModes:占位,不会受其它情况所影响而停止循环。
  • NSModalPanelRunLoopMode:运行循环等待输入时应将这种模式从模态面板,程序员无法使用。
  • NSEventTrackingRunLoopMode:将这种模式运行循环模式地跟踪事件,程序员无法使用。
29、多线程,线程锁,队列
  • NSThread
  • GCD
  • NSOperation

总的就先这些吧,东西也算是不少了,如果有说的不清楚的地方可以自行百度,也可以留言哈。
当然,也可以参考大佬的总结:
2018 iOS面试题系列
iOS面试题09- 基础篇
.
.
.

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,636评论 5 468
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 83,890评论 2 376
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,680评论 0 330
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,766评论 1 271
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,665评论 5 359
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,045评论 1 276
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,515评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,182评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,334评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,274评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,319评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,002评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,599评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,675评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,917评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,309评论 2 345
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,885评论 2 341

推荐阅读更多精彩内容