iOS一道复合型面试题与底层原理
Posted iOS开发
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了iOS一道复合型面试题与底层原理相关的知识,希望对你有一定的参考价值。
Python实战社群
Java实战社群
长按识别下方二维码,按需求添加
扫码关注添加客服
进Python社群▲
扫码关注添加客服
进Java社群▲
作者丨收納箱
原文链接:
https://juejin.im/post/5f0687035188252e685d2dab
0. 引言
我们常常吐槽面试的难度,甚至出现了 “面试造火箭,开发拧螺丝” 说法。作为客户端开发人员,面试直接让你现场手撸一个红黑树,难度是很大的,除非你专门准备过。
但常见的考点我们是需要知道的。有时考点可能被包装了一下,可能没法一下就看出来,但看破考点之后就会有恍然大悟的感觉。因为本质还是一样的,都是新瓶装旧酒。就像原来的理科考试题,包装一个新的场景,让你解决这个场景下的一个问题,但理论知识都是学过的。
好了,下面废话不多说,进入我们的问题。
1. 面试题
1.1 题目
我们从热身开始,慢慢深入:
面试题1
现有一个继承于NSObject的实例对象,需要在不直接修改方法实现的情况下,改变一个方法的行为,你会怎么做?
不直接修改方法实现,指的是不直接修改.m文件中方法的内部实现
这一道题比较简单,其实问的就是 Runtime 的 Method Swizzling 。可能答出来之后,还会问几个 Method Swizzling 相关的深入问题。下面难度升级。
面试题2
问题1,如果使用 Method Swizzling 技术,相当于修改了类对象中方法选择器和IMP实现的对应关系。这将导致继承自这个类的所有子类和实例对象都影响,如何控制受影响的范围,或者说如何让方法的行为改变只对这个实例对象生效?
这个题难度上升了,但是不是有一种脱离生产的感觉,为了面试你而出的一道题?
我们对这个问题包装一下,让它看起来更接地气,同时问题也再升级一点。
面试题3
现有一个视图,我们需要扩大一下它的响应范围。如果使用 Method Swizzling 技术,受影响的范围会比较大。当然,也可以选择继承一个子类来实现。但如果现在实例已经创建了,还是同样的需求,你会如何实现?
现在问题开始接近生产了。一般来说,修改响应范围涉及到 响应链和事件传递 的知识点。
- hitTest:withEvent:
- pointInside:withEvent:现在限制了继承并创建子类实例 的方案,只能选择其他办法。
现在同样也限制了 Method Swizzling 方案,还有什么办法呢?
答案还是 Runtime 技术。但这个会涉及到2个 Runtime 考点:消息发送与转发 以及 isa-swizzling 。
消息发送与转发:主要是 objc_msgSend 之后的方法查找流程。如果继续深入问,会到 消息转发 相关的考点。
isa-swizzling :常见于 KVO 原理考点,但其实说到 isa-swizzling 肯定会伴随着 消息发送与转发 问题。因为修改了isa的指向,执行 objc_msgSend 时的查找流程会发生变化。
如果回答 Method Swizzling 技术,又涉及到影响范围问题,可能需要加开关、加扩大响应范围记录的变量等,则又涉及到 关联对象 相关的问题。
如果可以继承,当然可以选择复写两个方法来解决。
其实,从第1问到第3问,问的核心都是 isa-swizzling ,但通过层层包装可能涉及到 多个知识点 ,变成一道复合型面试题。
1.2 示例
我们来写一个例子:
@interface Person : NSObject
@property (nonatomic, strong, nullable) NSString *firstName;
@property (nonatomic, strong, nullable) NSString *lastName;
@end
@implementation Person
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
Person *person = [[Person alloc] init];
person.firstName = @"Tom";
person.lastName = @"Google";
NSLog(@"person full name: %@ %@", person.firstName, person.lastName);
}
@end
现在要在创建了person实例后,修改lastName的返回值,将其固定返回 Apple 。
@interface Person : NSObject
@property (nonatomic, strong, nullable) NSString *firstName;
@property (nonatomic, strong, nullable) NSString *lastName;
@end
@implementation Person
@end
NSString *demo_getLastName(id self, SEL selector)
{
return @"Apple";
}
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
Person *person = [[Person alloc] init];
person.firstName = @"Tom";
person.lastName = @"Google";
NSLog(@"person full name: %@ %@", person.firstName, person.lastName);
// 1.创建一个子类
NSString *oldName = NSStringFromClass([person class]);
NSString *newName = [NSString stringWithFormat:@"Subclass_%@", oldName];
Class customClass = objc_allocateClassPair([person class], newName.UTF8String, 0);
objc_registerClassPair(customClass);
// 2.重写get方法
SEL sel = @selector(lastName);
Method method = class_getInstanceMethod([person class], sel);
const char *type = method_getTypeEncoding(method);
class_addMethod(customClass, sel, (IMP)demo_getLastName, type);
// 3.修改修改isa指针(isa swizzling)
object_setClass(person, customClass);
NSLog(@"person full name: %@ %@", person.firstName, person.lastName);
Person *person2 = [[Person alloc] init];
person2.firstName = @"Jerry";
person2.lastName = @"Google";
NSLog(@"person2 full name: %@ %@", person2.firstName, person2.lastName);
}
@end
// 输出
person full name: Tom Google
person full name: Tom Apple
person2 full name: Jerry Google
从输出结果可以看到,我们使用 isa-swizzling 将person对象lastName的行为改变了,而person2对象没有受到影响。
我们一般知道 isa-swizzling 是 KVO 的底层原理,但不能只知道拿来做 KVO 。
我想通过这个面试题,介绍一种如何在日常开发中使用 isa-swizzling 的思路。
下面是 KVO 原理,如果你非常自信已经熟悉这部分内容,可以不看了~
如果觉得这个面试题对你有所帮助,给我点个赞吧~
以上是关于iOS一道复合型面试题与底层原理的主要内容,如果未能解决你的问题,请参考以下文章
提升--08---LockSupport淘宝面试题与源码阅读方法论