美文网首页
面试题总结

面试题总结

作者: sunnyxg0812 | 来源:发表于2020-02-11 10:18 被阅读0次

    1:block 本质

    block 本质是一个 C++ 结构体,编译的时候编译器会把Block的表达式及Block变量,编译成结构体和函数,block调用就是函数指针调用,Block表达式中使用局部变量时,被捕获的变量会生成为 block 的成员变量,编译生成的结构体(__main_block_impl_0)会持有该变量,该结构体会带着默认值初始化结构体实例,内部的成员变量impl(struck__block_impl impl)包含了面向对象的基础和 block 内部代码逻辑的实现,内部的构造函数(__main_block_impl_0)则执行了赋值操作,完成了结构体变量的初始化。block实际上也是一个oc对象,他的第一个成员是__block_impl结构体,而__block_impl第一个成员就是isa指针,默认指向_NSConcreteStackBlock类,block是封装了函数调用以及函数调用环境的OC对象。

    2:runLoop的原理

    RunLoop是与线程相关的基础架构中的一部分,它是一个处理事件的循环,用来处理程序运行过程中出现的各种事件(比如说触摸事件、UI刷新事件、定时器事件、Selector事件),RunLoop 在没有事件处理的时候,会使线程进入睡眠模式,从而节省 CPU 资源,提高程序性能。当有持续的异步任务需求时,我们会创建一个独立的生命周期可控的线程,RunLoop就是控制线程生命周期并接收事件进行处理的机制。它和线程是一一对应的,每个线程都有一个对应的RunLoop对象,主线程的RunLoop会在程序启动时自动创建,子线程需要手动获取来创建。

    3:什么是runtime?

    runtime是OC的重要特性,使得OC语言具有动态的特性,动态指的是,能够在运行时,动态的创建类和对象,进行消息传递和转发。

    runtime其实就是将编译期间的决策推迟到运行时再决定,只有在程序运行时,才去检查对象的类型和方法的实现,利用这一特性能够在程序运行时,改变对象的类型和方法的实现。

    4:什么是isa指针?有什么作用?

    isa是对象中,用来指向它的类的指针,通过isa可以访问这个类的所有父类。

    从runtime源码可以了解到,objc_object 和 objc_class两个结构体:

    objc_object 代表一个实例变量,objc_class代表一个类,两个结构体中同样都有一个isa指针,但是指向不同。

    objc_object指向它的类,也就objc_class

    objc_class指向元类(每个类,都有一个元类,用来存放类的类方法列表)

    objc_object实例变量,通过isa指针从objc_class中寻找实例变量,实例方法,和协议。如果没有找到,通过super_class指针,到父类中寻找,直到根类为止。

    任何NSObject子类的元类都使用NSObject的元类作为自己的所属类,而基类的元类中的isa指针指向它自己,这样就行程一个完美的闭环。

    总结:OC中,isa指针是用来维护对象和类之间的关系,并确保对象和类能够通过isa指针找对对应的变量、方法和协议。

    5:NSString *obj = [[NSData alloc] init]; 编译时和运行时obj分别是什么类型?

    编译时obj为NSString类型,运行时为NSData类型。

    6:runtime如何实现weak变量的自动置为nil功能?

    runtime维护了一个weak表,用于存储指向某个对象的所有weak指针。weak表其实是一个hash(哈希)表,Key是所指对象的地址,Value是weak指针的地址(这个地址的值是所指对象指针的地址)数组。这样形成一个key-value的键值对,当引用计数变为0的时候,系统通过key-value查找指向weak变量的地址,将变量赋值为nil。

    weak 的实现原理可以概括一下三步:

    1、初始化时:runtime会调用objc_initWeak函数,初始化一个新的weak指针指向对象的地址。

    2、添加引用时:objc_initWeak函数会调用 objc_storeWeak() 函数, objc_storeWeak() 的作用是更新指针指向,创建对应的弱引用表。

    3、释放时,调用clearDeallocating函数。clearDeallocating函数首先根据对象地址获取所有weak指针地址的数组,然后遍历这个数组把其中的数据设为nil,最后把这个entry从weak表中删除,最后清理对象的记录。

    7:能否向编译后得到的类中增加实例变量?能否向运行时创建的类中添加实例变量?为什么?

    不能向编译后得到的类中增加实例变量。 

    能向运行时创建的类中添加实例变量。 

     解释下: 

     因为编译后的类已经注册在 runtime 中,类结构体中的 objc_ivar_list 实例变量的链表和 instance_size 实例变量的内存大小已经确定,同时 runtime 会调用 class_setIvarLayout 或 class_setWeakIvarLayout 来处理 strong weak 引用。所以不能向存在的类中添加实例变量。

     运行时创建的类是可以添加实例变量,调用 class_addIvar 函数。但是得在调用 objc_allocateClassPair 之后,objc_registerClassPair 之前,原因同上。 

    8:消息转发个流程

     Person*xiaoming=[[Person alloc]init];

    [xiaoming eat];
      1)对象通过isa找到它的类对象

    (2)在类对象的缓存方法列表中寻找eat方法

    (3)如果缓存中没有,就到当前类的方法列表中寻找

    (4)如果方法列表中没有,就通过superclass到父类的方法列表中寻找

    (5)如果父类方法类别也没有,那么就动态解析(Method Resolution)

    (6)如果消息解析后还没找到,那么就消息转发(Method Forwarding)

    (7)如果还是没找到,程序就崩溃,如果2~6步骤中有一个找到,则返回对应的函数实现(IMP)

    1.动态方法解析:动态添加方法

    解决代码中因为方法未找到而报错的问题;

    //OC方法:

    //类方法未找到时调起,可于此添加类方法实现

    + (BOOL)resolveClassMethod:(SEL)sel

    //实例方法未找到时调起,可于此添加实例方法实现

    + (BOOL)resolveInstanceMethod:(SEL)sel

    //Runtime方法:

    /**

    运行时方法:向指定类中添加特定方法实现的操作

    @param cls 被添加方法的类

    @param name selector方法名

    @param imp 指向实现方法的函数指针

    @param types imp函数实现的返回值与参数类型

    @return 添加方法是否成功

    */

    BOOL class_addMethod(Class _Nullable cls,

                        SEL _Nonnull name,

                        IMP _Nonnull imp,

                        const char * _Nullable types)

    2:消息接收者重定向

    如果目标对象实现了-forwardingTargetForSelector:,Runtime 这时就会调用这个方法,给你把这个消息转发给其他对象的机会。

    //重定向类方法的消息接收者,返回一个类

    - (id)forwardingTargetForSelector:(SEL)aSelector

    //重定向实例方法的消息接受者,返回一个实例对象

    - (id)forwardingTargetForSelector:(SEL)aSelector

    3:消息重定向

    如果在上一步还不能处理未知消息,则唯一能做的就是启用完整的消息转发机制了。

    首先它会发送-methodSignatureForSelector:消息获得函数的参数和返回值类型。如果-methodSignatureForSelector:返回nil,Runtime则会发出-doesNotRecognizeSelector:消息,程序这时也就挂掉了。如果返回了一个函数签名,Runtime就会创建一个NSInvocation对象并发送-forwardInvocation:消息给目标对象。

    - (NSMethodSignature*)methodSignatureForSelector:(SEL)aSelector;

    - (void)forwardInvocation:(NSInvocation *)anInvocation;

    9:ARC环境下,Autorelease对象什么时候释放?

    在不同的@autoreleasepool中,对象的释放时机不同,在iOS中分为两种情况:

    (1)如果在iOS工程中不手动添加@autoreleasepool,所有对象由main函数中的@autorelease管理,那么在一个runloop循环结束后,会清理自动释放池中的对象。

    (2)如果在iOS工程中手动添加了@autoreleasepool,并在其中创建了对象,那么当对象出了这个@autorelease作用域时会释放。

    不管哪种情况,都是通过push操作将对象存入对象,pop操作释放对象。

    10:ARC环境下,需不需要手动添加@autoreleasepool?

    在ARC环境下,main函数的@autoreleasepool处理了所有自动释放对象,编译器处理所有release对象。一般情况下,不需要手动添加自动释放池。但是在一些特殊情况下,需要我们手动添加。

    比如:使用@autoreleasepool来避免内存使用峰值太高的情况。如果你编写的循环中创建了大量的临时对象,使用@autoreleasepool。

    11:字符串内存管理

        NSString*str1 =@"str1";

        NSString*str2 =@"str2";

        NSString*str3 = [[NSStringalloc]initWithString:@"str3"];

        NSString*str4 = [NSStringstringWithString:@"str4"];

        NSString*str5 = [NSStringstringWithFormat:@"%@",@"123456789"];

        NSString*str6 = [NSStringstringWithFormat:@"%@",@"1234567890"];

    输出结果

    把字符串的初始化方式分为了两类:

    第一类是__NSCFConstantString:后面是带withString的(直接=@"xx"这种归入此类)。

    属于__NSCFConstantString类,__NSCFConstantString代表的是一个字符串常量,即便对其进行 release 操作,retainCount 也不会产生任何变化。是创建之后便是放不掉的对象。相同内容的 __NSCFConstantString 对象的地址相同,也就是说常量字符串对象是一种单例。这种对象存储在字符串常量区。

    第二类是__NSCFString:后面带withFormat的。

    __NSCFString对象是在运行时创建的一种NSString子类,他并不是一种字符串常量。所以和其他的对象一样在被创建时获得了1的引用计数。通过NSString的stringWithFormat等方法创建的NSString对象一般都是这种类型。这种对象被存储在堆上。

    这种初始化方式的字符串有一个阈值(建议使用数字来进行测试),字符串长度>9的时候,字符创的类型是__NSCFString,<=9时是NSTaggedPointerString类型。

    __NSCFString 表示对象类型的字符串,我们可以把他理解为正常的符合内存管理规则的那种字符串。该种类型字符串通过format方式创建。

    NSTaggedPointerString 类型的字符串是对__NSCFString类型的一种优化,在运行时创建字符串时,会对字符串内容及长度作判断,若内容由ASCII字符构成且长度较小,这时候创建的字符串类型就是 NSTaggedPointerString (标签指针字符串),字符串直接存储在指针的内容中。NSTaggedPointerString 理解这个类型,需要明白什么是标签指针,这是苹果在 64 位环境下对NSString,NSNumber等对象做的一些优化。简单来讲可以理解为把指针指向的内容直接放在了指针变量的内存地址中,因为在 64 位环境下指针变量的大小达到了 8 位足以容纳一些长度较小的内容。于是使用了标签指针这种方式来优化数据的存储方式。从他的引用计数可以看出,这货也是一个释放不掉的单例常量对象。在运行时根据实际情况创建。

    对于NSString对象来讲,当非字面值常量数字,英文字母字符串的长度小于等于9的时候会自动成为NSTaggedPointerString类型,如果有中文或其他特殊符号(可能是非 ASCII 字符)存在的话则会直接成为 )__NSCFString类型。

    这种对象被直接存储在指针的内容中,可以当作一种伪对象。

    相关文章

      网友评论

          本文标题:面试题总结

          本文链接:https://www.haomeiwen.com/subject/wkvtfhtx.html