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

0. 引言

我们常常吐槽面试的难度,甚至出现了 “面试造火箭,开发拧螺丝” 说法。作为客户端开发人员,面试直接让你现场手撸一个红黑树,难度是很大的,除非你专门准备过。

但常见的考点我们是需要知道的。有时考点可能被包装了一下,可能没法一下就看出来,但看破考点之后就会有恍然大悟的感觉。因为本质还是一样的,都是新瓶装旧酒。就像原来的理科考试题,包装一个新的场景,让你解决这个场景下的一个问题,但理论知识都是学过的。

好了,下面废话不多说,进入我们的问题。

1. 面试题

1.1 题目

我们从热身开始,慢慢深入:

  • 面试题1

    现有一个继承于NSObject的实例对象,需要在不直接修改方法实现的情况下,改变一个方法的行为,你会怎么做?

    不直接修改方法实现,指的是不直接修改.m文件中方法的内部实现

    这一道题比较简单,其实问的就是 RuntimeMethod Swizzling 。可能答出来之后,还会问几个 Method Swizzling 相关的深入问题。下面难度升级。

  • 面试题2

    问题1,如果使用 Method Swizzling 技术,相当于修改了类对象中方法选择器和IMP实现的对应关系。这将导致继承自这个类的所有子类和实例对象都影响,如何控制受影响的范围,或者说如何让方法的行为改变只对这个实例对象生效?

    这个题难度上升了,但是不是有一种脱离生产的感觉,为了面试你而出的一道题?

    我们对这个问题包装一下,让它看起来更接地气,同时问题也再升级一点。

  • 面试题3

    现有一个视图,我们需要扩大一下它的响应范围。如果使用 Method Swizzling 技术,受影响的范围会比较大。当然,也可以选择继承一个子类来实现。但如果现在实例已经创建了,还是同样的需求,你会如何实现?

    现在问题开始接近生产了。一般来说,修改响应范围涉及到 响应链和事件传递 的知识点。

    • 如果可以继承,当然可以选择复写两个方法来解决。
      • - hitTest:withEvent:
      • - pointInside:withEvent:

    现在限制了继承并创建子类实例 的方案,只能选择其他办法。

    • 如果回答 Method Swizzling 技术,又涉及到影响范围问题,可能需要加开关、加扩大响应范围记录的变量等,则又涉及到 关联对象 相关的问题。

    现在同样也限制了 Method Swizzling 方案,还有什么办法呢?

    答案还是 Runtime 技术。但这个会涉及到2个 Runtime 考点:消息发送与转发 以及 isa-swizzling

    • 消息发送与转发:主要是 objc_msgSend 之后的方法查找流程。如果继续深入问,会到 消息转发 相关的考点。
    • isa-swizzling :常见于 KVO 原理考点,但其实说到 isa-swizzling 肯定会伴随着 消息发送与转发 问题。因为修改了isa的指向,执行 objc_msgSend 时的查找流程会发生变化。

其实,从第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 *

你可能感兴趣的:(ios,xcode,objective-c,swift,面试)