iOS一道复合型面试题与底层原理

Posted iOS开发

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了iOS一道复合型面试题与底层原理相关的知识,希望对你有一定的参考价值。

Python实战社群

Java实战社群

长按识别下方二维码,按需求添加

扫码关注添加客服

进Python社群▲

iOS一道复合型面试题与底层原理

扫码关注添加客服

进Java社群


作者丨收納箱

原文链接:

https://juejin.im/post/5f0687035188252e685d2dab


iOS一道复合型面试题与底层原理


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一道复合型面试题与底层原理的主要内容,如果未能解决你的问题,请参考以下文章

iOS中__block 关键字的底层实现原理

提升--08---LockSupport淘宝面试题与源码阅读方法论

工作六年总结的Java面试题与经验

2021最全iOS面试题及底层视频分享专栏

分享一道面试题:模拟Spring IOC 控制反转实现原理,建议收藏!

一道面试题目