美文网首页面试常见问题全网最新iOS面试题-大厂加薪篇iOS面试
iOS开发跳槽入职小米,捋了一下iOS面试知识点

iOS开发跳槽入职小米,捋了一下iOS面试知识点

作者: iOS弗森科 | 来源:发表于2021-07-09 13:53 被阅读0次

    前言

    大概捋了一下iOS面试知识点,以此作为大纲希望自己能有目标有计划地准备面试,后面我会逐个复习一下相应的内容,同时也会添加遗漏的知识点到文本,并记录下自己的笔记分享出来。喜欢的可以收藏,大家一起努力。

    以下是小编收集总结的iOS技术点+面试题分类;看看你都会了吗?

    重点总结-几大分类:

    • iOS底层原理
    • 性能优化以及架构
    • 多线程、网络
    • 数据结构算法

    iOS底层原理(必问):iOS开发必备能力,也是大厂面试快速筛选人才方式之一。

    面试官问:

    一、性能优化点
    二、项目难点,怎么解决的
    三、项目流程迅游有品控审核和reviewcode
    四、http怎么发送数据tcp3次握手
    五、智能指针,智能指针有什么缺陷
    六、释放不干净(举例a=b b=a这种情况)


    51、数组和链表的区别
    - 数组在内存上给出了连续的空间
    - 链表,内存地址上可以是不连续的,每个链表的节点包括原来的内存和下一个节点的信息(单向的一个,双向链表的话,会有两个)
    
    数组: 
    - 优点: 使用方便,查询效率比链表高,内存为一连续的区域 
    - 缺点: 大小固定,不适合动态存储,不方便动态添加
    
     链表: 
    - 优点: 可动态添加删除,大小可变   
    - 缺点: 只能通过顺次指针访问,查询效率低
    
    
    53、谈谈你对编译、链接的理解

    电子版 iOS面试题+答案:

    文章由于答案太多,我做了一个PDF文档,由于简书不能上传文件,,由于文章有限,需要这些文档的,

    点击腾讯文档自取吧

    展示部分截图:↓↓↓↓↓

    iOS面试文档
    54、leak工具使用
    55、应用程序启动过程,启动优化
    - 应用启动时是用怎样加载所有依赖的Mach-O文件的?
    - 请列举你所知道main()函数之前耗时的因素都有哪些
    
    App启动分为两种:
    - 冷启动(Cold Launch):从零开始启动app
    - 热启动(Warm Launch):app已在内存中,在后台存活,再次点击图标启动app
    
    启动时间的优化,主要是针对冷启动进行优化
    1、通过添加环境变量可以打印app的启动时间分析(详情请见下图)
    - DYLD_PRINT_STATISTICS
    - DYLD_PRINT_STATISTICS_DETAILS(比上一个详细)
    - 一般400毫秒以内正常
    
    打印结果:
    Total pre-main time: 238.05 milliseconds (100.0%)              // main函数调用之前(pre-main)总耗时
             dylib loading time: 249.65 milliseconds (104.8%)      // 动态库耗时 
            rebase/binding time: 126687488.8 seconds (18128259.6%) 
                ObjC setup time:  10.67 milliseconds (4.4%)        // OC结构体准备耗时 
               initializer time:  52.83 milliseconds (22.1%)       // 初始化耗时 
               slowest intializers :                               // 比较慢的加载 
                 libSystem.B.dylib :   6.63 milliseconds (2.7%)
       libBacktraceRecording.dylib :   6.61 milliseconds (2.7%)
        libMainThreadChecker.dylib :  31.82 milliseconds (13.3%)
    
    2、冷启动可以概括为3大阶段
    - dyld
    - runtime
    - main
    
    3、dyld(dynamic link editor),Apple的动态连接器,可以装载Mach-O(可执行文件、动态库等)
    - 装载app的可执行文件,同时递归加载所有依赖的动态库
    - 当dyld把可执行文件、动态库都装载完成后,会通知runtime进行下一步处理
    
    4、runtime所做的事情
    - 调用map_images函数中调用call_load_methods,调用所有Class和Category的+load方法
    - 进行各种objc结构的初始化(注册objc类、初始化类对象等等)
    - 调用C++静态初始化器和__attribure__((constructor))修饰的函数(JSONKit中存在具体应用)
    - 到此为止,可执行文件和动态库中所有的符号(Class, Protocol, Selector, IMP...)都已按格式成功加载到内存中,被runtime所管理
    
    5、总结
    - app的启动由dylb主导,将可执行文件加载到内存,顺便加载所有依赖的动态库
    - 并由runtime负责加载成objc定义的结构
    - 所有初始化工作结束后,dyld就会调用main函数
    - 接下来就是ApplicationMain函数,AppDelegate的application:didFinishLaunchingWithOptions:方法
    
    6、按照不同的阶段优化
    dyld
    - 减少动态库、合并一些动态库(定期清理不必要的动态库)
    - 减少objc类、分类的数量、减少selector数量(定期清理不必要的类、分类)
    - 减少C++虚构函数
    - Swift尽量使用struct
    
    runtime
    - 使用+initialize方法和dispatch_once取代所有的__attribute__((constructor))、C++静态构造器、Objc的+load方法
    
    main
    - 在不影响用户体验的前提下,尽可能将一些操作延迟,不要全部都放在finishLaunching方法中
    - 按需加载
    
    
    DYLD_PRINT_STATISTICS设置为1
    56、包体积优化
    安装包瘦身(ipa):资源文件、可执行文件
    
    资源文件(图片、音频、视频等)
    - 采取无损压缩(使用工具)
    - 去除没有用到的资源(https://github.com/tinymind/LSUnusedResources)
    
    可执行文件瘦身:
    - 编译器优化(Xcode相关配置)
    - 利用AppCode(https://www.jetbrains.com/objc/)检测未使用的代码:菜单栏 -> Code -> Inspect Code
    - 生成LinkMap,可以查看可执行文件的具体组成
    - 可借助第三方工具解析LinkMap文件:http://github.com/huanxsd/LinkMap
    
    
    57、项目的优化、性能优化
    启动速度:
    - 启动过程中做的事情越少越好(尽可能将多个接口合并)
    - 不在UI线程上作耗时的操作(数据的处理在子线程进行,处理完通知主线程刷新节目)
    - 在合适的时机开始后台任务(例如在用户指引节目就可以开始准备加载的数据)
    - 尽量减小包的大小
    - 辅助工具(友盟,听云,Flurry)
    
    页面浏览速度
    - json的处理(iOS 自带的NSJSONSerialization,Jsonkit,SBJson)
    - 数据的分页(后端数据多的话,就要分页返回,例如网易新闻,或者 微博记录)
    - 数据压缩(大数据也可以压缩返回,减少流量,加快反应速度)
    - 内容缓存(例如网易新闻的最新新闻列表都是要缓存到本地,从本地加载,可以缓存到内存,或者数据库,根据情况而定)
    - 延时加载tab(比如app有5个tab,可以先加载第一个要显示的tab,其他的在显示时候加载,按需加载
    - 算法的优化(核心算法的优化,例如有些app 有个 联系人姓名用汉语拼音的首字母排序)
    
    操作流畅度优化
    - Tableview 优化(tableview cell的加载优化)
    - ViewController加载优化(不同view之间的跳转,可以提前准备好数据)
    
    
    58、说说你自己吧
    - 你在项目中技术亮点、难点
    - 你的发展方向(职业规划)
    - 你的优点、你的缺点
    
    
    59、说说组件化,你是如何组件化解耦的
    TODO(待填充);⌛️⌛️⌛️⌛️⌛️
    
    
    60、静态库、动态库相关
    1、什么是库?
    - 共享代码,实现代码的复用,一般分为静态库和动态库。
    
    2、静态库和动态库的区别
    静态库(.a和.framework 样式):
    - 链接时完整的拷贝到可执行文件,多次使用多次拷贝,造成冗余,使包变的更大
    - 但是代码装载速度快,执行速度略比动态库快
    
    动态库:(.dylib和.framework)
    - 链接时不复制,程序运行时由系统加在到内存中,供系统调用,系统加在一次,多次使用,共用节省内存。
    
    3、为什么framework既是静态又是动态?
    - 系统的framework是动态的,自己创建的是静态的。
    
    4、.a 和 .framework 的区别是什么?
    - .a 是单纯的二进制文件,需要 .h文件配合,不能直接使用
    - .framework是二进制文件+资源文件,可以直接使用。 .framework = .a + .h + sorrceFile(资源文件)
    
    

    十三、OC对象相关

    61、对 OC 中 Class 的源码理解?其中 cache 的理解?说说NSCache缓存策略
    struct objc_class {
        Class _Nonnull isa  OBJC_ISA_AVAILABILITY;
    
    #if !__OBJC2__
        Class _Nullable super_class                              OBJC2_UNAVAILABLE;
        const char * _Nonnull name                               OBJC2_UNAVAILABLE;
        long version                                             OBJC2_UNAVAILABLE;
        long info                                                OBJC2_UNAVAILABLE;
        long instance_size                                       OBJC2_UNAVAILABLE;
        struct objc_ivar_list * _Nullable ivars                  OBJC2_UNAVAILABLE;
        struct objc_method_list * _Nullable * _Nullable methodLists                    OBJC2_UNAVAILABLE;
        struct objc_cache * _Nonnull cache                       OBJC2_UNAVAILABLE;
        struct objc_protocol_list * _Nullable protocols          OBJC2_UNAVAILABLE;
    #endif
    
    } OBJC2_UNAVAILABLE;
    /* Use `Class` instead of `struct objc_class *` */
    
    
    62、protocol中能否添加属性
    - OC语言的协议里面是支持声明属性的
    - 但在协议中声明属性其实和在其中定义方法一样,只是声明了getter和setter方法,并没有具体实现
    
    
    63、OC内联函数 inline
    作用:
    - 替代宏
    
    inline函数与宏有区别
    - 解决函数调用效率的问题
    - 函数之间调用,是内存地址之间的调用,当函数调用完毕之后还会返回原来函数执行的地址。
    - 函数调用有时间开销,内联函数就是为了解决这一问题
    
    inline相比于宏的优点
    - 避免了宏的缺点:需要预编译.因为inline内联函数也是函数,不需要预编译.
    - 编译器在调用一个内联函数时,会首先检查它的参数的类型,保证调用正确。消除了它的隐患和局限性。
    - 可以使用所在类的保护成员及私有成员
    
    inline相比于函数的优点
    - inline函数避免了普通函数的,在汇编时必须调用call的缺点:取消了函数的参数压栈,减少了调用的开销,提高效率.所以执行速度确比一般函数的执行速度要快.
    - 集成了宏的优点,使用时直接用代码替换(像宏一样)
    
    
    64、id和NSObject ,instancetype的区别?
    - id和instancetype都可以做方法的返回值。
    
    - id类型的返回值在编译期不能判断对象的真实类型,即非关联返回类型
    - instancetype类型的返回值在编译期可以判断对象的真实类型,即关联返回类型。
    
    - id可以用来定义变量, 可以作为返回值, 可以作为形参
    - instancetype只能用于作为返回值。
    
    非关联返回类型、关联返回类型
    TODO(待填充);⌛️⌛️⌛️⌛️⌛️
    
    
    65、方法签名有什么作用?
    TODO(待填充);⌛️⌛️⌛️⌛️⌛️
    
    
    66、nil、Nil、NULL、NSNull的区别?
    - nil:指向一个对象的空指针    
    - Nil:指向一个类的空指针,   
    - NULL:指向其他类型(如:基本类型、C类型)的空指针, 用于对非对象指针赋空值.
    - NSNull:在集合对象中,表示空值的对象.
    
    NSNull在Objective-C中是一个类 .NSNull有 + (NSNull *)null; 单例方法.多用于集合(NSArray,NSDictionary)中值为空的对象.
    
    NSArray *array = [NSArray arrayWithObjects: [[NSObject alloc] init], [NSNull null], @"aaa", nil, [[NSObject alloc] init], [[NSObject alloc] init], nil];
    NSLog(@"%ld", array.count);// 输出 3,NSArray以nil结尾
    
    
    67、NSDictionary底层实现原理
    - 在OC中NSDictionary是使用hash表来实现key和value的映射和存储的。
    
    hash表存储过程简单介绍:
    - 根据key值计算出它的hash值h;
    - 假设箱子的个数是n,那么键值对应该放在第(h%n)个箱子中。
    - 如果该箱子中已经有了键值对,就是用开放寻址法或者拉链法解决冲突。使用拉链法解决哈希冲突时,每个箱子其实是一个链表,属于同一个箱子的所有键值对都会排列在链表中。
    
    
    68、父类的property是如何查找的?
    - 子类中的propert_list、method_list、ivar_list并不包含父类
    - 子类对象的_IMPL包含父类的
    
    从以上几点回答
    TODO(待填充);⌛️⌛️⌛️⌛️⌛️
    
    
    69、+load与 +initialize
    共同点:
    - 方法只会执行一次
    - 在类使用之前,就自动调用了这两个方法
    
    区别:
    - 执行时机不同()
    
    - load方法:如果类自身没有定义,并不会调用其父类的load方法;
    - initialize方法:如果类自身没有定义,就会调用其父类的initialize方法;
    
    执行的前提条件:
    - load 只要类所在文件被引用,就会执行; 
    - 如果类没有引用进项目,就不会有load的执行; 
    - initialize 需要类或者其子类的第一个方法被调用,才会执行,而且是在第一个方法执行之前,先执行; 
    - 即使类文件被引用进项目,但是没有使用,那么initialize就不会调用执行;
    
    
    70、iOS如何实现多继承,代码书写一下
    - 使用协议组合
    - NSProxy
    
    TODO(待填充);⌛️⌛️⌛️⌛️⌛️
    
    
    71、类与结构体的区别
    - 结构体只能封装数据,而类还可以封装行为
    - 赋值:结构体是拷贝,对象之间是地址
    - 结构体变量分配在栈空间(如果是一个局部变量的情况下),而对象分配在堆空间
    
    
    72、crash崩溃怎么解,崩溃到底层代码
    NSSetUncaughtExceptionHandler可以统计闪退
    TODO(待填充);⌛️⌛️⌛️⌛️⌛️
    
    
    73、属性、成员变量、set、get方法相关
    - 属性可以与set方法和get方法 三者同时存在吗,如果不行,请说明原因?
    换句话说就是:iOS中同时重写属性的set与get方法时,为什么访问不了下划线属性?
    
    原因:
    - 属性的setter方法和getter方法是不能同时进行重写,
    - 因为,一旦你同时重写了这两个方法,那么系统就不会帮你生成这个成员变量了
    
    解决方式:
    @synthesize authType = _authType;
    - 意思是,将属性的setter,getter方法,作用于这个变量。
    
    
    74、isa和superclass相关
    1、对象的isa指针指向哪里?superclass指针呢?(⚠️图-总结图)
    - instance的isa指向class
    - class的isa指向meta-class
    - meta-class的isa指向基类的meta-class
    
    - class的superclass指向父类的class(如果没有父类,superclass指针为nil)
    - meta-class的superclass指向父类的meta-class
    - ⚠️基类的meta-class的superclass指向基类的class
    
    2、方法调用查找(⚠️⚠️⚠️图-instance调用对象的轨迹;图-类方法调用轨迹)
    - 对象方法的调用:通过instance的isa找到class,最后找到对象方法的实现进行调用
    - 类方法的调用:当调用类方法时,通过class的isa找到meta-class,最后找到类方法的实现进行调用
    
    3、class对象的superclass指针
    Student : Person : NSObject
    
    当Student的instance对象要调用Personal的对象方法时:
    - 先通过isa找到Student的class,然后通过superclass找到Person的class,最后找到对象方法的实现进行调用
    
    4、meta-class对象的superclass指针
    当Student的class要调用Person的类方法时
    - 先通过isa找到Student的meta-class,然后通过superclass找到Person的meta-class,最后找到类方法的实现进行调用
    
    
    image image image image image image
    75、OC的类信息存放在哪里?
    - 对象方法、属性、成员变量、协议信息,存放在class对象中
    - 类方法,存放在meta-class对象中
    - 成员变量的具体值,存放在instance对象中
    
    

    76、class、meta-class的结构

    struct objc_class : objc_object {
        Class ISA;
        Class superclass;
        cache_t cache;             // 方法缓存
        class_data_bits_t bits;    // 用于获取具体的类信息
    }
    
    & FAST_DATA_MASK
    
    struct class_rw_t {
        uint32_t flags;
        uint32_t version;
        const class_ro_t *ro;        // 
        method_array_t methods;      // 方法列表
        property_array_t properties; // 属性列表
        protocol_array_t protocols;  // 协议列表
        Class firstSubclass;
        Class nextSiblingClass;
        char *demangledName;
    }
    
    struct class_ro_t {
        uint32_t flags;
        uint32_t instanceStart;
        uint32_t instanceSize;
    #ifdef __LP64__
        uint32_t reserved;
    #endif
    
        const uint8_t * ivarLayout;
        
        const char * name; // 类名
        method_list_t * baseMethodList;
        protocol_list_t * baseProtocols;
        const ivar_list_t * ivars; // 成员变量列表
    
        const uint8_t * weakIvarLayout;
        property_list_t *baseProperties;
    }
    

    推荐阅读:iOS热门面试技术文集

    相关文章

      网友评论

        本文标题:iOS开发跳槽入职小米,捋了一下iOS面试知识点

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