厦门IOS培训
达内厦门iOS培训中心

0592-5903858

热门课程

2018-iOS面试题(一)

  • 时间:2018-03-12 15:31
  • 发布:厦门达内
  • 来源:网络

1.KVO实现原理?

KVO在Apple中的API文档如下: 

Automatic key-value observing is implemented using a technique called isa-swizzling… When an observer is registered for an attribute of an object the isa pointer of the observed object is modified, pointing to an intermediate class rather than at the true class …

KVO基本原理:

1.KVO是基于runtime机制实现的

2.当某个类的属性对象第一次被观察时,系统就会在运行期动态地创建该类的一个派生类,在这个派生类中重写基类中任何被观察属性的setter 方法。派生类在被重写的setter方法内实现真正的通知机制

3.如果原类为Person,那么生成的派生类名为NSKVONotifying_Person

4.每个类对象中都有一个isa指针指向当前类,当一个类对象的第一次被观察,那么系统会偷偷将isa指针指向动态生成的派生类,从而在给被监控属性赋值时执行的是派生类的setter方法

5.键值观察通知依赖于NSObject 的两个方法: willChangeValueForKey: 和 didChangevlueForKey:;在一个被观察属性发生改变之前, willChangeValueForKey:一定会被调用,这就 会记录旧的值。而当改变发生后,didChangeValueForKey:会被调用,继而 observeValueForKey:ofObject:change:context: 也会被调用。

KVO深入原理:

1.Apple 使用了 isa 混写(isa-swizzling)来实现 KVO 。当观察对象A时,KVO机制动态创建一个新的名为: NSKVONotifying_A的新类,该类继承自对象A的本类,且KVO为NSKVONotifying_A重写观察属性的setter 方法,setter 方法会负责在调用原 setter 方法之前和之后,通知所有观察对象属性值的更改情况。

2.NSKVONotifying_A类剖析:在这个过程,被观察对象的 isa 指针从指向原来的A类,被KVO机制修改为指向系统新创建的子类 NSKVONotifying_A类,来实现当前类属性值改变的监听;

3.所以当我们从应用层面上看来,完全没有意识到有新的类出现,这是系统“隐瞒”了对KVO的底层实现过程,让我们误以为还是原来的类。但是此时如果我们创建一个新的名为“NSKVONotifying_A”的类(),就会发现系统运行到注册KVO的那段代码时程序就崩溃,因为系统在注册监听的时候动态创建了名为NSKVONotifying_A的中间类,并指向这个中间类了。

4.(isa 指针的作用:每个对象都有isa 指针,指向该对象的类,它告诉 Runtime 系统这个对象的类是什么。所以对象注册为观察者时,isa指针指向新子类,那么这个被观察的对象就神奇地变成新子类的对象(或实例)了。) 因而在该对象上对 setter 的调用就会调用已重写的 setter,从而激活键值通知机制。

5.子类setter方法剖析:KVO的键值观察通知依赖于 NSObject 的两个方法:willChangeValueForKey:和 didChangevlueForKey:,在存取数值的前后分别调用2个方法: 被观察属性发生改变之前,willChangeValueForKey:被调用,通知系统该keyPath 的属性值即将变更;当改变发生后, didChangeValueForKey: 被调用,通知系统该 keyPath 的属性值已经变更;之后, observeValueForKey:ofObject:change:context: 也会被调用。且重写观察属性的setter 方法这种继承方式的注入是在运行时而不是编译时实现的。

2.说说你理解的埋点?

以下几篇文章写的相当不错,可以适当借鉴下!

  • iOS无埋点数据SDK实践之路

  • iOS无埋点数据SDK的整体设计与技术实现

  • iOS无埋点SDK 之 RN页面的数据收集


3.消息转发机制原理?

消息转发机制基本分为三个步骤:

  1. 动态方法解析

  2. 备用接受者

  3. 完整转发


新建一个HelloClass的类,定义两个方法:

@interfaceHelloClass:NSObject

- (void)hello;

+ (HelloClass *)hi;@end

动态方法解析

对象在接收到未知的消息时,首先会调用所属类的类方法+resolveInstanceMethod:(实例方法)或者+resolveClassMethod:(类方法)。在这个方法中,我们有机会为该未知消息新增一个”处理方法”“。不过使用该方法的前提是我们已经实现了该”处理方法”,只需要在运行时通过class_addMethod函数动态添加到类里面就可以了。

void functionForMethod(id self, SEL _cmd)

{

    NSLog(@"Hello!");

}

Class functionForClassMethod(id self, SEL _cmd)

{

    NSLog(@"Hi!");

    return [HelloClass class];

}

#pragma mark - 1、动态方法解析

+ (BOOL)resolveClassMethod:(SEL)sel

{

    NSLog(@"resolveClassMethod");

    NSString *selString = NSStringFromSelector(sel);

    if ([selString isEqualToString:@"hi"])

    {

         Class metaClass = objc_getMetaClass("HelloClass");

         class_addMethod(metaClass, @selector(hi), (IMP)functionForClassMethod, "v@:");

         return YES;

    }

    return [super resolveClassMethod:sel];

}

+ (BOOL)resolveInstanceMethod:(SEL)sel

{

    NSLog(@"resolveInstanceMethod");

    NSString *selString = NSStringFromSelector(sel);

    if ([selString isEqualToString:@"hello"])

    {

         class_addMethod(self, @selector(hello), (IMP)functionForMethod, "v@:");

         return YES;

    }

    return [super resolveInstanceMethod:sel];

}


备用接受者

动态方法解析无法处理消息,则会走备用接受者。这个备用接受者只能是一个新的对象,不能是self本身,否则就会出现无限循环。如果我们没有指定相应的对象来处理aSelector,则应该调用父类的实现来返回结果。

#pragma mark - 2、备用接收者


- (id)forwardingTargetForSelector:(SEL)aSelector

{

    NSLog(@"forwardingTargetForSelector");

    NSString *selectorString = NSStringFromSelector(aSelector);

    // 将消息交给_helper来处理    if ([selectorString isEqualToString:@"hello"]) {

        return _helper;

    }

    return [super forwardingTargetForSelector:aSelector];

}

在本类中需要实现这个新的接受对象

@interfaceHelloClass()

{

    RuntimeMethodHelper *_helper;

}

@end

@implementationHelloClass- (instancetype)init

{

    self = [super init];

    if (self)

    {

         _helper = [RuntimeMethodHelper new];

    }

    return self;

}


RuntimeMethodHelper 类需要实现这个需要转发的方法:


#import"RuntimeMethodHelper.h"

@implementationRuntimeMethodHelper- (void)hello

{

    NSLog(@"%@, %p", self, _cmd);

}@end

完整消息转发

如果动态方法解析和备用接受者都没有处理这个消息,那么就会走完整消息转发:

#pragma mark - 3、完整消息转发


- (void)forwardInvocation:(NSInvocation *)anInvocation

{

    NSLog(@"forwardInvocation");

    if ([RuntimeMethodHelper instancesRespondToSelector:anInvocation.selector]) {

        [anInvocation invokeWithTarget:_helper];

    }

}

/*必须重新这个方法,消息转发机制使用从这个方法中获取的信息来创建NSInvocation对象*/

- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector

{

    NSMethodSignature *signature = [super methodSignatureForSelector:aSelector];

    if (!signature)

    {

        if ([RuntimeMethodHelper instancesRespondToSelector:aSelector])

        {

            signature = [RuntimeMethodHelper instanceMethodSignatureForSelector:aSelector];

        }

    }

    return signature;

}

上一篇:程序员面试必看!BAT面试题和面试技巧集锦!
下一篇:2018-iOS面试题(二)

2018最新iOS面试题精选总结

2018年最新iOS面试题及答案

整理2018年iOS面试题

各大企业常见的ios面试题之一

选择城市和中心
贵州省

广西省

海南省