美文网首页
没有多大用处的八股文

没有多大用处的八股文

作者: E术家 | 来源:发表于2022-11-06 10:30 被阅读0次

    Swift中struct和class的区别

    struct是值引用,存放于栈区,更轻量,class是类型引用,存放于堆区。struct无法继承,class可以继承。

    Swift中的方法调用

    直接派发、函数表派发、消息机制派发。派发方式受声明位置,引用类型,特定行为的影响。

    Swift和OC的区别

    swift:静态语言、更精简、存在命名空间、方法调用方式多、存在泛型、元组、高阶函数、性能更高、速度更快。
    OC:动态语言、消息转发、面向对象

    Swift面向协议编程

    面向协议则是用协议的方式组织各个类的关系,Swift底层几乎所有类都构建在协议之上。
    面向协议能够解决面向对象的菱形继承,横切关注点和动态派发的安全性等问题。

    OC中的block

    block本质是一个对象,底层用struct实现。

    struct Block_descriptor {   
          unsigned long int reserved;    
          unsigned long int size;    
          void (*copy)(void *dst, void *src);      
          void (*dispose)(void *);  
    };
    struct Block_layout {    
          void *isa;    
          int flags;    
          int reserved;    
          void (*invoke)(void *, ...);    
          struct Block_descriptor *descriptor;   
         /* Imported variables. */
    };
    

    isa 指针,所有对象都有该指针,用于实现对象相关的功能。
    flags,用于按 bit 位表示一些 block 的附加信息,本文后面介绍 block copy 的实现代码可以看到对该变量的使用。
    reserved,保留变量。invoke,函数指针,指向具体的 block 实现的函数调用地址。
    descriptor, 表示该 block 的附加描述信息,主要是 size 大小,以及 copy 和 dispose 函数的指针。
    variables,capture 过来的变量,block 能够访问它外部的局部变量,就是因为将这些变量(或变量的地址)复制到了结构体中。

    __block的作用是可以获取对应变量的指针,使其可以在block内部被修改。通过反编译的代码我们可以看到该对象是这样的:

    struct __Block_byref_i_0 {
    
        void *__isa;
    
        __Block_byref_i_0 *__forwarding;
    
        int __flags;
    
        int __size;
    
        int val; //变量名
    
    };
    

    GCD中的Block是在堆上。

    NSCoding协议

    一种编码协议,归档时和解档时需要依赖该协议定义的编码和解码方法。Foundation和Cocoa Touch中的大部分类都遵循了这个协议,一般被NSKeyedArchiver做自定义对象持久化时使用。

    KVO的实现原理

    利用Runtime生成一个中间对象,让原对象的isa指针指向它,然后重写setter方法,插入willChangeValueForKey和didChangeValueForKey方法。当属性变化时会调用,会调用这两个方法通知到外界属性变化。

    NSOperation的特性

    NSOperation是对GCD的封装,具有面向对象的特点,可以更方便的进行封装,可以设置依赖关系。
    NSNotificaiton是同步,如果发通知时在子线程,接收在子线程。

    事件响应链

    手势的点击会发生两个重要事情,事件传递和事件响应。

    事件传递:从UIApplication开始,到window,再逐步往下层(子视图)找,直到找到最深层的子视图,其为first responder。用到的判断方法是pointInside:withEvent和hitTest:withEvent。

    事件响应:从识别到的视图(first responder)开始验证能否响应事件,如果不能就交给其上层(父视图)视图,如果能相应将不再往下传递,如果直到找到UIApplication层还没有相应,那就忽略该次点击。用到的判断方法是touchesBegan:withEvent、touchesMoved:withEvent等。

    异步渲染

    异步渲染就是在子线程进行绘制,然后拿到主线程显示。UIView的显示是通过CALayer实现的,CALayer的显示则是通过contents进行的。异步渲染的实现原理是当我们改变UIView的frame时,会调用layer的setNeedsDisplay,然后调用layer的display方法。我们不能在非主线程将内容绘制到layer的context上,但我们单独开一个子线程通过CGBitmapContextCreateImage()绘制内容,绘制完成之后切回主线程,将内容赋值到contents上。

    layoutsubviews调用时机

    init初始化不会触发。
    addSubview时。
    设置frame且前后值变化,frame为zero且不添加到指定视图不会触发。
    旋转Screen会触发父视图的layoutSubviews。
    滚动UIScrollView引起View重新布局时会触发layoutSubviews。

    离屏渲染

    如果要在显示屏上显示内容,我们至少需要一块与屏幕像素数据量一样大的frame buffer,作为像素数据存储区域。
    如果有时因为面临一些限制,无法把渲染结果直接写入frame buffer,而是先暂存在另外的内存区域,之后再写入frame buffer,那么这个过程被称之为离屏渲染。
    以阴影为例,为什么它会导致离屏渲染。因为GPU的渲染是遵循“画家算法”,一层一层绘制的,但阴影很特殊,它需要全部内容绘制完成,再根据外轮廓进行绘制。
    这就导致了,阴影这一层要一直占据一块内存区域,这就导致了离屏渲染。
    类似导致离屏渲染的情况还有:cornerRadius+clipsToBoundsgroup opacity 组透明度mask 遮罩UIBlurEffect 毛玻璃效果。

    CoreAnimation & UIKit

    CoreAnimation虽然直译是核心动画,但它其实是一个图像渲染框架,动画实现只是它的一部分功能。是UIKit和AppKit的底层实现,位于Metal、Core Graphics和GPU之上之上。

    ARC方案的原理

    ARC(Automatic Reference Cunting)自动引用计数,意即通过LLVM编译器自动管理对应的引用计数状态。ARC开启时无需再次键入retain或者release代码。

    它是在编译阶段添加retain或者release代码的。

    避免循环引用

    循环引用及两个及以上对象出现引用环,导致对象无法释放的情况。一般在block,delegate,NSTimer时容易出现这个问题。

    解决方案就是让环的其中一环节实现弱引用。

    为什么当我们在使用block时外面是weak 声明一个weakSelf,还要在block内部使用strong再持有一下?

    block外界声明weak是为了实现block对对象的弱持有,而里面的作用是为了保证在进到block时不会发生释放。

    Autoreleasepool是实现机制是什么?它是什么时候释放内部的对象的?它内部的数据结构是什么样的?当我提到哨兵对象时,会继续问哨兵对象的作用是什么,为什么要设计它?

    Autoreleasepool的原理是一个双向列表,它会对加入其中的对象实现延迟释放。当Autoreleasepool调用drain方法时会释放内部标记为autorelease的对象。

    class AutoreleasePoolPage {    
            magic_t const magic;    
            id *next;    
            pthread_t const thread;    
            AutoreleasePoolPage * const parent;    
            AutoreleasePoolPage *child;    
            uint32_t const depth;    
            uint32_t hiwat;
    };
    

    哨兵对象类似一个指针,指向自动释放池的栈顶位置,它的作用就是用于标记当前自动释放池需要释放内部对象时,释放到那个地方结束,每次入栈时它用于确定添加的位置,然后再次移动到栈顶。

    哪些对象会放入到Autoreleasepool中?

    有两种情况生成的对象会加入到autoreleasepool中:
    非alloc/new/copy/mutablecopy 开始的方式初始化时。
    id的指针或对象的指针在没有显示指定时

    weak的实现原理是什么?当引用对象销毁是它是如何管理内部的Hash表的

    runTime会把对weak修饰的对象放到一个全局的哈希表中,用weak修饰的对象的内存地址为key,weak指针为值,在对象进行销毁时,用通过自身地址去哈希表中查找到所有指向此对象的weak指针,并把所有的weak指针置位nil。

    Runtime

    消息发送的流程

    OC中的方法调用会转化成给对象发送消息,发送消息会调用这个方法:objc_msgSend(receiver, @selector(message))
    该过程有以下关键步骤:
    先确定调用方法的类已经都加载完毕,如果没加载完毕的话进行加载
    从cache中查找方法
    cache中没有找到对应的方法,则到方法列表中查,查到则缓存
    如果本类中查询到没有结果,则遍历所有父类重复上面的查找过程,直到NSObject

    关联对象时什么情况下会导致内存泄露

    关联对象可以理解就是持有了一个对象,如果是retain等方式的持有,而该对象也持有了本类,那就是导致了循环引用。

    消息转发的流程

    消息转发是发生在接收者(receiver)没有找到对应的方法(method)的时候,该步骤有如下几个关键步骤:
    消息转发的时候,如果是实例方法会走resolveInstanceMethod:,如果是类方法会走resolveClassMethod:,它们的返回值都是Bool,需要我们确定是否进行转发。
    如果第一步返回YES,确定转发就会进到下个方法forwardingTargetForSelector,这个方法需要我们指定一个被用receiver。
    methodSignatureForSelector用于指定方法签名,forwardInvocation用于处理Invocation,进行完整转发。
    如果消息转发也没有处理即为无法处理,会调用doesNotRecognizeSelector,引发崩溃。

    category能否添加属性,为什么?能否添加实例变量,为什么?

    可以添加属性,这里的属性指@property,但跟类里的@property又不一样。正常的@property为:实例变量Ivar + Setter + Getter 方法,分类里的@property这三者都没有,需要我们手动实现。
    分类是运行时被编译的,这时类的结构已经固定了,所以我们无法添加实例变量。
    对于分类自定义Setter和Getter方法,我们可以通过关联对象(Associated Object)进行实现。

    元类的作用

    元类的作用是存储类方法,同时它也是为了让OC的类结构能够形成闭环。
    对于为甚设计元类有以下原因;
    在OC的世界里一切皆对象(借鉴于Smalltalk),metaclass的设计就是要为满足这一点。
    在OC中Class也是一种对象,它对应的类就是metaclass,metaclass也是一种对象,它的类是root metaclass,在往上根元类(root metaclass)指向自己,形成了一个闭环,一个完备的设计。
    如果不要metaclass可不可以?也是可以的,在objc_class再加一个类方法指针。但是这样的设计会将消息传递的过程复杂化,所以为了消息传递流程的复用,为了一切皆对象的思想,就有了metaclass。

    类方法、类属性的存储地

    类方法和类属性都是存储到元类中的。
    类属性在Swift用的多些,OC中很少有人用到,但其实它也是有的,写法如下:

    @interface Person : NSObject
    
    // 在属性类别中加上class
    
    @property (class, nonatomic, copy) NSString *name;
    
    @end
    
    // 调用方式
    
    NSString *temp = Person.name;
    

    需要注意的是跟实例属性不一样,类属性不会自动生成实例变量和setter,getter方法,需要我们手动实现。

    runtime的应用场景

    hook系统方法进行方法交换。
    了解一个类(闭源)的私有属性和方法。
    关联对象,实现添加分类属性的功能。
    修改isa指针,自定义KVO。

    Runloop

    检测卡顿
    线程保活
    性能优化,将一些耗时操作放到runloop wait的情况处理。

    对TableView进行性能优化

    缓存高度
    异步渲染
    减少离屏渲染

    缩小包体积

    图片压缩,无用图片删除
    一些大图可以动态下发
    删除无用类,无用方法
    减少三方库的依赖

    项目编译的流程

    编译流程:
    预处理:处理宏定义,删除注释,展开头文件。
    词法分析:把代码切成一个个token,比如大小括号等于号还有字符串
    语法分析:验证语法是否正确,合成抽象语法树AST
    静态分析:查找代码错误
    类型检查:动态和静态
    目标代码的生成与优化,包括删除多余指令,选择合适的寻址方式,如果开启了bitcode,会做进一步的优化
    汇编:由汇编器生成汇编语言
    机器码:由汇编语言转成机器码,生成.o文件

    应用启动的流程:
    启动的前提是完成编译,运行程序即运行编译过后的目标程序,它分为main函数前和main函数后:
    main前
    加载可执行文件(App的.o文件集合)
    加载动态链接库(系统和应用的动态链接库),进行rebase指针调整和bind符号绑定
    Objc运行时的初始处理,包括Objc相关类的注册,category注册,selector唯一性检查
    初始化,包括执行+load()、attribute(constructor)修饰的函数的调用、创建C++静态全局变量
    main后
    首页初始化所需要配置文件的读写操作
    首页界面渲染

    对于基本数据类型,一般是存储到栈中的,它有没有可能存在堆上,什么情况下会存储到堆上?

    栈和堆都是同属一块内存,只不过一个是高地址往低地址存储,一个从低地址往高地址存储,他们并没有严格的界限说一个值只能放在堆上或者栈上。所以基本数据类型也是可以存储到堆上的。

    当该基础类型变量被__block捕获时,该变量连同block都会被copy到堆上。

    数据库中的事务是什么意思?

    事务就是访问并操作各种数据项的一个数据库操作序列,这些操作要么全部执行,要么全部不执行。如果其中一个步骤出错就要撤销整个操作,回滚到进入事务之前的状态。

    LRU算法

    LRU(Least recently used 最近最少使用)算法是一个缓存淘汰算法,其作用就是当缓存很多时,该淘汰哪些内容,见名知意,它的核心思想是淘汰最近使用最少的内容。实现它的关键步骤是:
    新数据插入到链表的头部
    每当缓存命中时,则将数据移动到链表头部
    链表满时,将尾部数据清除
    这个算法在SDWebImage和Kingfisher等需要处理缓存的库中都有实现。

    设计模式

    工厂模式、观察者模式、中介者模式、单例模式。

    如果有1000万个Int类型的数字,如何对他们排序?

    这里的隐藏含义是,内存不够用时如何排序,还有一个隐藏含义是硬盘足够大。这是可以采用分而治之的方法,将数据分成若干块,使每一小块满足当前内容大小,然后对每块内容单独排序,最后采用归并排序对所有块进行排序,就得到了一个有序序列。

    设计一套数据库方案,实现类似微信的搜索关键词能快速检索出包含该字符串的聊天信息,并展示对应数量(聊天记录的数据量较大)

    可以对聊天记录的文本值加上索引。正常情况下数据库搜索都是全量检索的,加上索引之后只会检索满足条件的记录,大大降低检索量。

    Lottie实现动画效果的原理

    iOS里的动画基本都是基于CoreAnimation里的API实现的,Lottie也是如此。在AE上实现动画效果,通过插件导出对应的json文件,Lottie的库解析该json,转成对应的系统API方法。图片的引用可以使用Base64编到json里,也可以通过项目集成,通过路径引用。

    静态库和动态库的区别

    静态库:链接时被完整复制到可执行文件中,多次使用就多份拷贝。
    动态库:链接时不复制,而是由系统动态加载到内存,内存中只会有一份该动态库。

    二进制重排的核心依据

    修改链接顺序,减少启动时的缺页中断。

    相关文章

      网友评论

          本文标题:没有多大用处的八股文

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