美文网首页面试题
IOS面试:基础题库(上)

IOS面试:基础题库(上)

作者: 时光啊混蛋_97boy | 来源:发表于2020-10-25 16:41 被阅读0次

    原创:知识点总结性文章
    创作不易,请珍惜,之后会持续更新,不断完善
    个人比较喜欢做笔记和写总结,毕竟好记性不如烂笔头哈哈,这些文章记录了我的IOS成长历程,希望能与大家一起进步
    温馨提示:由于简书不支持目录跳转,大家可通过command + F 输入目录标题后迅速寻找到你所需要的内容

    目录

    • 宏观题
    • 一、KVO
    • 二、Runtime
    • 三、网络
    • 四、多线程
    • 五、Block
    • 六、OC对象
    • 七、Category
    • 八、内存管理
    • 九、RunLoop
    • 十、View
    • 十一、通知和委托
    • 十二、性能优化和安全
    • 十三、框架和架构
    • 十四、Swift
    • 十五、图像音视频
    • 十六、本地缓存
    • 十七、数据结构和算法
    • 十八、其他系统框架
    • 十九、设计模式

    宏观题

    1、谈安卓与苹果的优缺点
    • 苹果系统优点是左右流畅,软件多,界面华丽,图标统一,很美观;缺点是系统封闭,不允许用户过多的个性化设置,而且只能在苹果手机上用。
    • 安卓系统优点是开放,可以自己扩展的东西很多,支持的硬件也多,各个价位的手机都有;缺点就是软件太杂乱,兼容性有问题,图标混乱不美观。
    • iOS的确比android流畅,这仅仅体现在较大软件切换时,其他差不多流畅。
    • iOS系统更新没有android那么频繁,爱体验的人会选安卓,那些怕烦的会选iOS。
    2、简单说一下APP的启 动过程,从main文件开始说起

    有storyboard情况下:
    1.main函数
    2.UIApplicationMain
    a、创建UIApplication对象;
    b、创建UIApplicationdelegate对象

    3.根据Info plist获得最主要story board的文件名, 加载最主要的storyboard(有launch storyboard)
    a、创建UIWindow;
    b、创建和设置UIWindowrootViewController;
    c、显示窗口

    没有storyboard情况下:
    1.main函数
    2.UIApplicationMain
    a、创建UIApplication对象;
    b、创建UIApplicationdelegate对象

    3.delegate对象开始处理(监听)系统事件(没有storyboard)
    a、程序启动完毕的时候,就会调用代理的application:didFinishI aunchingWithOptions:方法
    b、在application:didFinishLaunchingWithOptions:中创建UIWindow
    c、创建和设置UIWindowrootViewController;
    d、显示窗口

    3、在提交苹果审核时,遇到哪些问题被拒绝,对于被拒绝的问题是如何处理的?

    app中有虚拟物品交易,但是没走内购导致被拒。
    音频类App或者使用到音频相关的app,因为版权问题而被拒。
    App出现必闪退而被拒。

    4、iOS应用程序的状态有哪些?

    Not running未运行:应用还没有启动,或者应用正在运行但是途中被系统停止
    Inactive未激活:应用正在前台运行但是不接收事件,(也许正在执行其他代码)。一般当应用要从一个状态切换到另一个不同状态时,中途过度会短暂停留在此状态。唯一在此状态停留事件较长的情况是:当用户锁屏时,或者系统提示用户去响应某些(如来电,有未读短信)事件的时候。
    Active激活:程序在前台运行而且接收到了事件。这也是前台的一个正常的模式。
    Backgroud后台:程序在后台而且能执行代码,大多数程序进入这个状态后会在在这个状态上停留一会,时间到之后会进入挂起状态(Suspended)。有的程序经过特殊的请求后可以长期处于Backgroud状态。如果一个程序要求启动时直接进入后台运行,这样的应用会直接从not running状态直接进入background状态,中途不会经过inactive状态。
    Suspended挂起:程序在后台不能执行代码。系统会自动把程序变成这个状态而且不会发出通知。当挂起时,程序还是停留在内存中的,当系统内存低时,系统就把挂起的程序清除掉,为前台程序提供更多的内存。

    刚启动时
    application:didFinishLaunchingWithOptions:
    applicationDidBecomeActive:
    进入后台时
    applicationWillResignActive:
    applicationDidEnterBackground:
    进入前台时
    applicationWillEnterForeground:
    applicationDidBecomeActive:

    5、Swift是面向对象还是函数式的编程语言?

    Swift 既是面向对象的,又是函数式的编程语言。说Swift是面向对象的语言,是因为Swift支持类的封装、继承、和多态。说Swift是函数式编程语言,是因为Swift支持map, reduce, filter这类去除中间状态、数学函数式的方法,更加强调运算结果而不是中间过程。

    6、请说明并比较Swift语言中的-些关键词: Open, Public, Internal, File-private, Private

    Swift 有五个级别的访问控制权限,从高到底依次为比如Open, Public, Intemal, File-private, Private

    他们遵循的基本原则是:
    高级别的变量不允许被定义为低级别变量的成员变量。比如一个privateclass中不能含有publicString。反之,低级别的变量却可以定义在高级别的变量中。比如publicclass中可以含有privateInt

    Open具备最高的访问权限。其修饰的类和方法可以在任意Module中被访问和重写;

    Public的权限仅次于Open。与Open唯一的区别在于它修饰的对象可以在任意Module中被访问,但不能重写。

    Intermal是默认的权限。它表示只能在当前定义的Module中访问和重写,它可以被一个Module中的多个文件访问,但不可以被其他的Module中被访问。

    File-pivate其被修饰的对象只能在当前文件中被使用。例如它可以被一个文件中的class, extension, struct共同使用。

    Private是最低的访问权限。它的对象只能在定义的作用域内使用。离开了这个作用域,即使是同一个文件中的其他作用域,也无法访问。

    7、编译过程做了哪些事情?

    C++, Objective C都是编译语言。编译语言在执行的时候,必须先通过编译器生成机器码,机器码可以直接在CPU上执行,所以执行效率较高。
    iOS开发目前的常用语言是: ObjctiveSwift。二者都是编译语言,换句话说都是需要编译才能执行的。二者的编译都是依赖于Clang +LLVM

    iOS编译:不管是OC还是Swift,都是采用Clang作为编译器前端,LLVM(Low level vritual machine)作为编译器后端。
    编译器前端的任务是进行:语法分析,语义分析,生成中间代码(intermediate representation)。在这个过程中,会进行类型检查, 如果发现错误或者警告会标注出来在哪一行。
    编译器后端会进行机器无关的代码优化,生成机器语言,并且进行机器相关的代码优化。

    LLVM机器码生成器会针对不同的架构,比如arm64等生成不同的机器码。
    编译各个m文件,使用CompileCclang命令。

    8、 C和Objective c如何混用

    objc的编译器处理后缀为m的文件时,可以识别obj-cc的代码,处理mm文件可以识别objc,c,c++代码,但cpp文件必须只能用c/c++代码,而且cpp文件include的头文件中。

    9、请解释一下启动画面 (Launch Images)

    启动应用程序后,进入主功能界面前会有一张图片或一段动画效果,停留数秒钟后消失。这张图片或这段动画效果我们称之为应用的启动画面。
    由于启动画面在每次打开应用时都会出现,并且停留很短的时间,就像闪现的效果一样,所以也有人把启动画面称之为闪屏。
    从用户体验的角度考虑,产品应当尽可能快的让用户进入程序并进行功能操作。如此看来,启动画面就是多余的存在。
    但是,应用程序本质上是由多种代码命令和数据组合而成的。启动应用程序的过程实质上是运行代码和数据读取的过程,而这个过程是需要一定时间的。
    与其给用户看代码运行的过程,不如给用户展示图片,这也是用户体验。

    10、AppDelegate扮演着什么样的角色?

    创建应用程序之后,默认有AppDelegate文件 。AppDelegate为整 个应用的一个代理,提供程序启动、退出等类似监控的接口,控制着应用的生命周期。

    11、iOS应用开发流程。

    注册APP ID
    注册成为苹果开发者
    创建开发证书、发布证书
    开发
    真机调试
    打包和发布
    等待审核
    上线

    一、KVO

    1、实现原理

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

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

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

    {
        // pre setting code here
        [self willChangeValueForKey: key];
        (*imp)(self, _cmd, val);
        // post setting code here
        [self didChangeValueForKey: key];
    }
    
    2、哪些情况下使用kvo会崩溃,怎么防护崩溃
    • KVO的被观察者dealloc时仍然注册着KVO导致的crash
    • KVO注册观察者与移除观察者次数不匹配,比如重复注册,多次移除
    3、如何手动触发KVO?
    • 手动调用willChangeValueForKey:和`didChangeValueForKey:
    • KVC会触发KVO,也会调用重写的set方法
    • 直接修改成员变量不会触发KVO,因为直接修改成员变量并没有走set方法
    4、KVO的观察者如果为weak,会有什么影响?

    set方法实际执行的是父类的 willchangge, setvalue 以及didchangge方法。 如果为weak,可能导致观察者被释放,而无法监测到值的变更。

    5、什么是KVC和KVO?

    KVO:键值监听,观察某一属性的方法
    KVC:键值编码,是一种间接访问对象的属性。

    KVC(Key-Value-Coding)内部的实现:一个对象在调用setValue的时候,
    键值编码是一种间接访问对象的属性,使用字符串来标识属性,而不是通过调用存取方法,直接通过实例变量访问的机制。

    KVC的缺点:一旦使用 KVC你的编译器无法检查出错误,即不会对设置的键、键路径进行错误检查, 且执行效率要低于合成存取器方法和自定的settergetter方法。因为使用 KVC 键值编码,它必须先解析字符串,然后在设置或者访问对象的实例变量。

    KVO (Key-Value- Observing) :
    当观察者为一个对象的属性进行了注册,被观察对象的isa指针被修改的时候,isa指针就会指向一个中间类,而不是真实的类。所以isa指针其实不需要指向实例对象真实的类。
    键值观察机制是一种能使得对象获取到其他对象属性变化的通知 ,极大的简化了代码。
    实现 KVO 键值观察模式,被观察的对象必须使用 KVC 键值编码来修 改它的实例变量,这样才能被观察者观察到。因此,KVC是KVO的基础。

    6、KVC和KV0的keyPath一定是属性么?

    keypath 就是属性链式访问
    KVC支持实例变量,KV0只能手动设定实例变量的KV0实现监听。

    7、如何给一个对象的私有属性赋值?

    利用KVC即键值编码来给对象的私有属性赋值。

    二、Runtime

    1、介绍下runtime的内存模型(isa、对象、类、metaclass、结构体的存储信息等)
    struct objc_object {
    private:
        isa_t isa;
    }
    
    struct objc_class : objc_object {
        // Class ISA;
        Class superclass;
        cache_t cache;             // formerly cache pointer and vtable
        class_data_bits_t bits;    // class_rw_t * plus custom rr/alloc flags
    };
    
    2、为什么要设计metaclass

    通过meta-class创建类对象

    3、消息发送,消息转发机制和其他语言的消息机制优劣对比
    • objc_msgSend流程: 判断receiver是否为nil,获取isacache查找,lookUpImpOrForward -> method list查找(线性或者二分查找),按照继承链(superclass)查找,走动态解析;
    • 动态解析: resolveMethod,再走method list查找,按照继承链(superclass)查找,走消息转发;
    • 消息转发: forwardingTargetForSelector转发到其他对象,重复走上述的 objc_msgSend流程。
    • 再走methodSignatureForSelector:方法 -> 随后走forwardInvocation:方法。
    4、super
    struct objc_super {
        /// Specifies an instance of a class.
        __unsafe_unretained _Nonnull id receiver;
    
        /// Specifies the particular superclass of the instance to message. 
        __unsafe_unretained _Nonnull Class super_class;
    #endif
        /* super_class is the first class to search */
    };
    
    objc_msgSendSuper(struct objc_super * _Nonnull super, SEL _Nonnull op, ...);
    
    5、Runtime用处
    • KVC
    • OC动态性由runtime支撑和实现
    • 关联对象(Objective-C Associated Objects)给分类增加属性
    • 方法魔法(Method Swizzling)方法添加和替换和KVO实现
    • 消息转发(热更新)解决Bug(JSPatch)
    • 实现NSCoding的自动归档和自动解档
    • 实现字典和模型的自动转换(MJExtension)
    6、给一个对象发消息,中间过程是怎样的?

    根据isa 查找(缓存,继承链) -> 动态解析(自身方法实现) -> 消息转发(转发、方法签名、invoke) -> 崩溃not recognise

    7、设计一个方案,在消息转发的阶段中统一处理掉找不到方法的这种crash

    resolveMethod中通过runtime增加方法

    8、什么是动态绑定?

    在编译时,方法的调用并不和代码绑定在一起,只有在消实发送出来之后,才确定消息的接收者和被调用的方法。

    9、我们说的oc是动态运行时语言是什么意思?

    主要是将数据类型的确定由编译时,推迟到了运行时。这个问题其实浅涉及到两个概念,运行时和多态。

    简单来说,运行时机制使我们直到运行时才去决定一个对象的类别,以及调用该类别对象指定方法。

    多态:不同对象以自己的方式响应相同的消息的能力叫做多态。意思就是假设生物类(life)都用有一个相同的方法-eat; 那人类属于生物,猪也属于生物,都继承了life后,实现各自的eat,但是调用是我们只需调用各自的eat方法。也就是不同的对象以自己的方式响应了相同的消息(响应了eat这个选择器)。因此也可以说, 运行时机制是多态的基础。在OC中动态类型id是实现多态的一种方式,id是一个独特的数据类型,可以转换为任何数据类型。

    10、响应者链

    响应者对象指的是有响应和处理事件能力的对象。
    响应者链就是由一系列的响应者对象构成的一个层次结构。

    UIResponder是所有响应对象的基类,在UIResponder类中定义了处理上述各种事件的接口。我们熟悉的UIApplicationUIViewControllerUIWindow和所有继承自UIViewUIKit类都直接或间接的继承自UIResponder,所以它们的实例都是可以构成响应者链的响应者对象。

    响应者链有以下特点:
    1、响应者链通常是由视图(UIView)构成的;
    2、一个视图的下一个响应者是它视图控制器(UIViewController)(如果有的话),然后再转给它的父视图(Super View);
    3、视图控制器(如果有的话)的下一个响应者为其管理的视图的父视图;
    4、单例的窗口(UIWindow)的内容视图将指向窗口本身作为它的下一个响应者
    5、单例的应用(UIApplication) 是一个响应者 链的终点,它的下一个响应者指向nil,以结束整个循环。

    11、runtime怎么添加属性、方法等

    给系统的类添加属性的时候可以使用runtime动态添加属性、方法。
    本质: 动态添加属性就是让某个属性与对象产生关联。
    class_ addIvar
    class_ addMethod
    class_ addProperty
    class_ addProtocol
    class_ replaceProperty

    12、runtime如何实现weak属性?

    weak策略表明该属性定义了一种非拥有关系(nonowning relationship)。为这种属性设置新值时,设置方法既不保留新值,也不释放旧值。此特质同assign类似,然而在属性所指的对象遭到摧毁时,属性值也会清空(nil)

    runtime对注册的类,会进行布局,会将weak对象放入一个hash表中。用weak指向的对象内存地址作为key,当此对象的引用计数为0的时候会调用对象的dealloc方法,假设weak指向的对象内存地址是a,那么就会以akey,在这个weak hash表中搜索,找到所有以akeyweak对象,从而设置为nil

    13、使用runtime Associate方法关联的对象,需要在主对象dealloc的时候释放么?

    被关联的对象在生命周期内要比对象本身释放的晚很多,它们会在被NSObject -dealloc调用的object_ _dispose方法中释放。

    14、_ objc_ msgForward函数是做什么的?直接调用它将会发生什么?

    _objc. _msgForwardIMP类型,用于消息转发的: 当向一个对象发送一条消息,但它并没有实现的时候,_ objc. msgForward会尝试做消息转发。

    直接调用_ _objc_ msgForward是非常危险的事,这是把双刃刀,如果用不好会直接导致程序Crash,但是如果用得好,能做很多非常酷的事。

    15、简述下Objective-C中调用方法的过程(runtime)

    Objective-C是动态语言,每个方法在运行时会被动态转为消息发送,即: objc_ msgSend(receiver,selector)整个过程介绍如下:

    objc在向一个对象发送消息时,runtime库会根据对象的isa指针找到该对象实际所属的类。然后在该类中的方法列表以及其父类方法列表中寻找方法运行。如果在最顶层的父类(一般也就NSObjcct)中依然找不到相应的方法时,程序在运行时会挂掉并抛出异常unrecognized selector sent to XXX。但是在这之前,objc的运行时会给出三次拯救程序崩溃的机会。

    补充说明: Runtime铸就了0bjective-C是动态语言的特性,使得C语言具备了面向对象的特性,在程序运行期创建,检查修改类、对象及其对应的方法,这些操作都可以使用runtime中的对应方法实现。

    16、什么是method swizling?

    简单说就是进行方法交换
    Objcctive-C中调用一个方法,其实是向一个对象发送消息, 查找消息的唯一依据是selector的名字。利用objctive-C的动态特性,可以实现在运行时偷换sclector对应的方法实现,达到给方法挂钩的目的。

    每个类都有一个方法列表,存放着方法的名字和方法实现的映射关系, selector的本质其实就是方法名,IMP有点类似函数指针,指向具体的Method实现,通过selector就可以找到对应的IMP

    交换方法的几种实现方式:
    利用method_ exchangelmplementations 交换两个方法的实现
    利用class replaceMethod 替换方法的实现
    利用method_ setlmplementation 来直接设置某个方法的IMP

    17、什么时候会报unrecognized selector的异常?

    当调用该对象上某个方法,而该对象上没有实现这个方法的时候,可以通过“消息转发’进行解决。objc是动态语言,每个方法在运行时会被动态转为消息发送,即: objc_ msgSend(receiver, selector)objc在向一个对象发送消息时,runtime库会根据对象的isa指针找到该对象实际所属的类,然后在该类中的方法列表以及其父类方法列表中寻找方法运行,如果在最顶层的父类中依然找不到相应的方法时,程序在运行时会挂掉并抛出异常unrecognized selector sent to XXX

    18、performSelector:withObject:afterDelay:内部大概是怎么实现的,有什么注意事项么?

    创建一个定时器时间结束后系统会使用runtime通过方法名称(Selector本质就是方法名称)去方法列表中找到对应的方法实现并调用方法。调用performSelctor:withObject:afterDelay:方法时先判断希望调用的方法是否存在respondsToSelector:。这个方法是异步方法,必须在主线程调用,在子线程调用永远不会调用到想调用的方法。

    19、class_copyIvarList & class_copyPropertyList区别

    class_copyPropertyList:通过类名获得类的属性变量。获得的是由@property修饰过的变量。
    class_copyIvarList:通过类名获得类的实例变量。获得的是class_copyPropertyList修饰的以及在m文件的中@implementation内定义的变量。

    20、load、initialize方法的区别什么?在继承关系中他们有什么区别?

    +load:在这个文件被程序装载时调用。只要是在Compile Sources中出现的文件总是会被装载,这与这个类是否被用到无关,因此+load方法总是在main函数之前调用。调用方式并不是采用runtimeobjc_msgSend方式调用的,而是直接采用函数的内存地址直接调用的; 多个类的load调用顺序,是依赖于compile sources中的文件顺序决定的,根据文件从上到下的顺序调用,子类和父类同时实现load的方法时,父类的方法先被调用本类与category的调用顺序是,优先调用本类的(注意:category是在最后被装载的) 。load是被动调用的,在类装载时调用的。

    initialize:当类或子类第一次收到消息时被调用(即:静态方法或实例方法第一次被调用,也就是这个类第一次被用到的时候),方式是通过runtimeobjc_msgSend的方式调用的,此时所有的类都已经装载完毕;子类和父类同时实现initialize,父类的先被调用,然后调用子类的;本类与category同时实现initializecategory会覆盖本类的方法,只调用categoryinitialize一次(这也说明initialize的调用方式采用objc_msgSend的方式调用的);initialize是主动调用的,只有当类第一次被用到的时候才会触发。

    三、网络

    1、四层结构

    应用层 -> http, DNS, ftp -> DNS(domain name system)
    传输层 -> tcp, UDP
    网络层 -> ip -> ARP(address resolution protocol)
    链路层

    2、请求报文 响应报文

    请求报文:请求方法、请求uri、协议版本、可选的请求首部、内容实体
    响应报文:协议版本、状态码、解释状态码的原因短语、可选的请求首部、内容实体

    3、url统一资源标识符

    http:// user:pass@ www.example.com: 80 /dir/index.html ?uid=1#ch
    协议 登录信息 服务器地址 端口 层次的路径 查询字符串

    4、请求方法

    GET: 获取资源
    POST: 传输实体主体
    PUT: 传输文件,不带验证机制
    HEAD: 获取报文首部
    DELETE: 删除文件
    OPTIONS: 询问支持的method
    TRACE: 追踪路径,查询发送出去的请求怎样被加工、篡改
    CONNECT: 邀请用隧道协议连接代理

    5、状态码

    1xx: 信息性状态码
    2xx: 成功状态码 200、204、206
    3xx: 重定向状态码 301、302、303、304、307
    4xx: 客户端错误 400、401、403、404
    5xx: 服务端错误 500、502、503、504

    6、HTTPS

    http的不足
    1、通信使用明文,内容可能被窃取
    2、不验证通信方的身份,因此可能遭遇伪装
    3、无法证明报文的完整性,所以有可能被篡改

    https = http + 加密 + 认证 + 完整性保护

    https(ssl,tsl)的不足
    1、消耗网络资源
    2、消耗cpu和内存等硬件资源

    7、socket连接与http连接

    http连接:短连接。即客户端向服务端发送一次请求,服务端响应之后,链接即会断掉。
    socket连接:长连接。即客户端一旦与服务器建立接连,便不会主动断掉。

    8、什么是可扩展标记语言extensible markup language XML ?

    XML指可扩展标记语言(EXtensible Markup Language)
    XML是一种标记语言,很类似HTML
    XML的设计宗旨是传输数据,而非显示数据
    XML标签没有被预定义。您需要自行定义标签。
    XML被设计为具有自我描述性。
    XML是W3C的推荐标准。

    9、XML与HTML的区别。

    XMLHTML的设计区别是:XML的核心是数据,其重点是数据的内容。而HTML被设计用来显示数据,其重点是数据的显示。

    XMLHTML语法区别:HTML的标记不是所有的都需要成对出现,XML则要求所有的标记必须成对出现;HTML标记不区分大小写,XML则大小敏感,即区分大小写。

    10、HTTP协议的主要特点。

    1.支持客户/服务器模式。
    2.简单快速:
    客户向服务器请求服务时,只需传送请求方法和路径。
    请求方法常用的有GETHEADPOST
    每种方法规定了客户与服务器联系的类型不同。
    由于HTTP协议简单,使得HTTP服务器的程序规模小,因而通信速度很快。

    3.灵活:HTTP允许传输任意类型的数据对象。正在传输的类型由Content-Type加以标记。

    4.无连接:
    无连接的含义是限制每次连接只处理一个请求。
    服务器处理完客户的请求,并收到客户的应答后,即断开连接。
    采用这种方式可以节省传输时间。

    5.无状态:
    HTTP协议是无状态协议。
    无状态是指协议对于事务处理没有记忆能力。
    缺少状态意味着如果后续处理需要前面的信息,则它必须重传,这样可能导致每次连接传送的数据量增大。
    另一方面, 在服务器不需要先前信息时它的应答就较快。

    11、TCP/UDP区别联系

    TCP---传输控制协议提供的是面向连接、可靠的字节流服务。
    当客户和服务器彼此交换数据前,必须先在双方之间建立一个TCP连接,之后才能传输数据。
    TCP提供超时重发,丢弃重复数据,检验数据,流量控制等功能,保证数据能从一端传到另一端。

    UDP---用户数据报协议,是一个简单的面向数据报的运输层协议。
    UDP不提供可靠性,它只是把应用程序传给IP层的数据报发送出去,但是并不能保证它们能到达目的地。
    由于UDP在传输数据报前不用在客户和服务器之间建立一个连接,且没有超时重发等机制,故而传输速度很快。

    12、socket连接和http连接的区别

    http连接:http连接就是所谓的短连接,即客户端向服务器端发送一次请求,服务器端响应后连接即会断掉;

    socket连接:
    socket连接就是所谓的长连接,理论上客户端和服务器端一旦建立起连接将不会主动断掉; 但是由于各种环境因素可能会导致连接断开,比如说:服务器端或客户端主机down了,网络故障,或者两者之间长时间没有数据传输,网络防火墙可能会断开该连接以释放网络资源。

    所以当一个socket连接中没有数据的传输,那么为了维持连接需要发送心跳消息,具体心跳消息格式是开发者自 己定义的。

    13、什么是TCP连接的三次握手?

    握手过程中传送的包里不包含数据,三次握手完毕后,客户端与服务器才正式开始传送数据。理想状态下,TCP连接一旦建立,在通信双方中的任何一方主动关闭连接之前,TCP 连接都将被一直保持下去。

    14、利用Socket建立网络连接的步骤?

    建立Socket连接至少需要一对套接字,其中一个运行于客户端,称为ClientSocket,另一个运行于服务器端,称为ServerSocket

    套接字之间的连接过程分为三个步骤: 服务器监听,客户端请求,连接确认。
    1。服务器监听:
    服务器端套接字并不定位具体的客户端套接字,而是处于等待连接的状态,
    实时监控网络状态,等待客户端的连接请求。

    2。客户端请求:
    指客户端的套接字提出连接请求,要连接的目标是服务器端的套接字。
    为此,客户端的套接字必须首先描述它要连接的服务器的套接字,指出服务器端套接字的地址和端口号,然后就向服务器端套接字提出连接请求。

    3。连接确认:
    当服务器端套接字监听到或者说接收到客户端套接字的连接请求时,就响应客户端套接字的请求,建立一个新的线程,把服务器端套接字的描述发给客户端,一旦 客户端确认了此描述,双方就正式建立连接。而服务器端套接字继续处于监听状态,继续接收其他客户端套接字的连接请求

    15、在App中混合HTML5开发App如何实现的。在App中使用HTML5的优缺点是什么?

    在iOS中,通常是UIWebView来实现,当然在iOS8以后可以使用WKWebView来实现。有以下几种实现方法:iOS加入H5响应比原生要慢很多,体验不太好,这是缺点。iOS加入H5可以实现嵌入别的功能入口,可随时更改,不用更新版本就可以上线,这是最大的优点。

    16、JSPatch使用了iOS的什么原理?

    通过JS调用和改写0C方法最根本的原因是Objective-C是动态语言,OC上所有方法的调用/类的生成都通过Objective-C Runtime在运行时进行。

    17、你使用过json解析方式么,他们的底层是如何处理的你了解么?

    底层原理遍历字符串中的字符,最终根据格式规定的特殊字符,比如{}号, []号, :号等进行区分,{}号是一个字典的开始,[]号是一 个数组的开始, :号是字典的键和值的分水岭,最终乃是将json数据转化为字典,字典中值可能是字典,数组,或字符串而已。

    18、iOS的签名机制大概是怎样的?

    签名机制:
    先将应用内容通过摘要算法,得到摘要
    再用私钥对摘要进行加密得到密文
    将源文本、密文、和私钥对应的公钥一并发布

    验证流程:
    查看公钥是否是私钥方的
    然后用公钥对密文进行解密得到摘要
    将APP用同样的摘要算法得到摘要,两个摘要进行比对,如果相等那么一切正常
    以上过程只要有一步出问题就视为无效。

    19、WKWebView的优点

    拥有60fps滚动刷新率
    内置手势
    高效的app和web信息交换通道
    Safari相同的JavaScript引擎

    四、多线程

    1、iOS开发中有多少类型的线程?分别对比

    pthread

    • C语言框架,跨平台,基本不用。
    • 手动管理生命周期。

    NSThread

    • pthread的封装,面向对象,比较少用。
    • 手动管理生命周期。
    • 不太适合复杂任务,比如涉及线程状态、线程依赖、线程同步等。

    GCD

    • 优化应用程序以支持多核处理器,自动管理线程的生命周期,不需要编写任何线程管理代码。
    • 控制起来比较麻烦,比如取消一个线程。
    • 无法对任务设置优先级。

    NSOperation

    • 面向对象,对gcd的封装
    • 可进行取消、暂停操作
    • 配合queue可以对任务设置优先级
    2、GCD有哪些队列,默认提供哪些队列?

    队列:serialconcurrentmainglobal
    同步异步:队列决定任务执行顺序,sync, async决定是否开启新线程

    3、GCD有哪些方法api?

    dispatch_syncdispatch_async
    dispatch_barrier_asyncdispatch_group_async
    dispatch_afterdispatch_once
    dispatch_applydispatch_semaphore

    4、如何实现同步,有多少方式就说多少?

    groupsemaphore、串行队列、加锁、barrier

    5、dispatch_once实现原理?

    系统级的信号量

    6、什么情况下会死锁

    禁止抢占(no preemption) :系统资源不能被强制从一个进程中退出。
    持有和等待(hold and wait):一个进程可以在等待时持有系统资源。
    互斥(mutual exclusion) :资源只能同时分配给一个行程,无法多个行程共享。
    循环等待(circular waiting) :一系列进程互相持有其他进程所需要的资源。

    7、有哪些类型的线程锁,分别介绍下作用和使用场景
    • 互斥锁:线程会进入休眠状态等待被唤醒
    • pthread_mutex 互斥锁,等待锁的线程会处于休眠状态
    • NSLockNSRecursiveLock 是对 pthread_mutex的封装
    • NSConditionLock
    • @synchronized
    • OSSpinLock 自旋锁:线程等待锁的线程仍然占用CPU资源,即忙等
    • 信号量 dispatch_semaphore:通过dispatch_semaphore_waitdispatch_semaphore_signal控制可访问线程的数量来达到同步的目的
    8、属性修饰符atomic的内部实现是怎么样的? 能保证线程安全吗?

    spinlock_t,真实底层实现为mutex_t中的os_unfair_lock
    能保证属性自身的读写是安全的,但不能保证属性内的值读写是安全的。

    9、NSOperationQueue中的maxConcurrentOperationCount默认值

    -1,表示不进行限制,由NSOperationQueue根据系统状态动态确定,支持并发操作。

    10、NSTimer、CADisplayLink、dispatch_source_t 的优劣

    前两者依赖runloop执行,作为timesource塞进mode的集合中。
    后者不依赖runloop,系统级,可取消。

    11、异步绘制过程中,将生成的image赋值给contents的这种方式,会有什么问题?

    设置image也是通过给layer.contents赋值来实现的;iOS要求所有的UI操作都必须在主线程上完成,所以如果在异步绘制完成image,就需要切换到主线程给contents赋值;

    12、Object C中创建线程的方法是什么?

    线程创建有三种方法: 使用NSThread创建 、使用GCDdispatch、使用子类化的NSOperation,然后将其加入NSOperationQueue;

    13、如果在主线程中执行代码,方法是什么?

    在主线程执行代码,方法是performSelectorOnMainThread

    14、如果想延时执行代码、方法是什么?

    如果想延时执行代码可以用performSelector:onThread:withObject:waitUntilDone:

    15、线程与进程的区别和联系

    进程和线程都是由操作系统所控制的程序运行的基本单元,系统利用该基本单元实现系统对应用的并发性。进程和线程的主要差别在于它们是不同的操作系统资源管理方式。

    进程有独立的地址空间,一个进程崩溃后,在保护模式下不会对其它进程产生影响,而线程只是一个进程中的不同执行路径。

    线程有自己的堆栈和局部变量,但线程没有单独的地址空间,一个线程死掉就等于整个进程死掉,所以多进程的程序要比多线程的程序健壮,但在进程切换时,耗费资源较大,效率要差一些。但对于一些要求同时进行并且又要共享某些变量的并发操作,只能用线程,不能用进程。

    16、NSTimer创建后,会在哪个线程运行?

    scheduledTimerWithTimeInterval创建的,在哪个线程创建就会被加入哪个线程的RunLoop中就运行在哪个线程。

    17、dispatch_ sync 和dispatch_ async区别是什么?

    dispatch_ async:异步队列,dispatch_ async函数会立即返回,block会在后台异步执行。
    dispatch_ sync:同步队列,dispatch_ sync函数不会立即返回,阻塞当前线程,等待block同步执行完成。

    18、以scheduledTimerWithTimeInterval的方式触发的timer,在滑动页面上的列表时,timer会暂停, 为什么?该如何解决?

    其一是将timer加入到NSRunloopCommonModes中。
    其二是将timer放到另一个线程中,然后开启另一个线程的runloop,这样可以保证与主线程互不干扰,而现在主线程正在处理页面滑动。

    19、GCD执行原理?

    GCD有一个底层线程池,这个池中存放的是一个个的线程。之所以称为“池”,很容易理解出这个“池”中的线程是可以重用的,当一段时间后这个线程没有被调用,这个线程就会被销毁。
    注意:开多少条线程是由底层线程池决定的,池是系统自动来维护。而程序员只关心的是向队列中添加任务,队列调度即可。

    如果队列中存放的是同步任务,则任务出队后,底层线程池中会提供一条线程供这 个任务执行,任务执行完毕后这条线程再回到线程池。这样队列中的任务反复调度,因为是同步的,所以当我们用currentThread打印的时候,就是同一条线程。

    如果队列中存放的是异步的任务,当任务出队后,底层线程池会提供一个线程供任务执行,因为是异步执行,队列中的任务不需等待当前任务执行完毕就可以调度下一个任务,这时底层线程池中会再次提供一个线程供第二个任务执行,执行完毕后再回到底层线程池中。

    这样就对线程完成一个复用,而不需要每一个任务执行都开启新的线程,也就从而节约的系统的开销,提高了效率。

    20、NSOperationQueue相对于GCD来说有哪些优点?

    可以很方便的取消一个NSOperation的执行
    可以更容易的添加任务的依赖关系
    提供了任务的状态: isExecuteing, isFinished
    可以通过设置maxConcurrentOperationCount属性来控制并发任务的数量

    21、请描述一下同步和异步,说说它们之间的区别。

    首先,我们要明确一点,同步和异步都是在线程中使用的。在iOS开发中,比如网络请求数据时,若使用同步请求,则只有请求成功或者请求失败得到响应返回后,才能继续往下走,也就是才能访问其它资源(会阻塞了线程)。网络请求数据异步请求时,不会阻塞线程,在调用请求后,可以继续往下执行,而不用等请求有结果才能继续。

    线程同步是多个线程访问同一资源时,只有当前正在访问的线程访问结束之后,其他线程才能开始访问(被阻塞)。线程异步是多个线程在访问竞争资源时,可以在空闲等待时去访问其它资源(不被阻塞)。

    22、 dispatch_ barrier_ async的作用是什么?

    在并行队列中,为了保持某些任务的顺序,需要等待一些任 务完成后才能继续进行,使用barrier来等待之前任务完成,避免数据竞争等问题。

    dispatch_ barrier async 函数会等待追加到Concurrent Dispatch Queue并行队列中的操作全部执行完之后,然后再执行dispatch_ barrier _async 函数追加的处理,等dispatch_ barrier _async追加的处理执行结束之后,Concurrent DispatchQueue才恢复之前的动作继续执行。

    23、Thread的创建分为显式和隐式两种类型

    显式方式

    Thread.detachNewThreadSelector(selector: toTarget: with:)
    Thread.init(target: selector: object:)
    

    隐式

    object.performSelector(inBackground: with:)
    object.performSelector(inBackground: afterDelay with: )
    
    24、 iOS提供了哪些类型的线程锁(保持线程同步的方式)

    NSLock
    RecursiveLock
    ConditionLock
    信号量
    pthread mutex
    @synchronized

    25、并发、串行、同步和异步描述

    并发:多个任务同时执行
    串行:一个任务执行完成后,再执行下一个任务
    同步:在当前线程中执行任务,不会开启新线程
    异步:在新的线程中执行任务

    26、CADisplayLink和Timer

    CADisplayLink使用场合相对专一,适合做UI的不停重绘。
    NSTimer的使用范围要广泛的多,各种需要单次或者循环定时处理的任务都可以使用。
    在UI相关的动画或者显示内容使用CADisplayLink比起用NSTimer的好处就是我们不需要再格外关心屏幕的刷新频率。
    CADisplayLink可用于自定义动画弓|擎或者视频播放的渲染。

    五、Block

    1、block的内部实现,结构体是什么样的?
    struct Block_layout {
        void *isa;
        volatile int32_t flags; // contains ref count
        int32_t reserved;
        void (*invoke)(void *, ...);
        struct Block_descriptor_1 *descriptor;
        // imported variables
        // 捕获对象时,编译器会增加对'variables'的内存管理方法
    };
    
    2、block是类吗,有哪些类型

    OC 对象,继承自NSObject,封装了函数调用。
    NSGlobalBlock: 在block内部为静态或者全局变量。
    NSStackBlock: block内部使用了auto修饰符的都是NSStackBlock类型
    NSMallocBlock: NSStackBlock调用copy得到的就是NSMallocBlock类型。

    3、block的变量截获
    • 局部变量值类型捕获其值
    • 对象连带修饰符一起捕获
    • 对于静态变量转化为指针
    • 全局变量不捕获,直接访问
    • forwarding:指向自己的指针,不管__block变量配置在栈上还是堆上,都能够正确地访问该变量
    4、block在修改NSMutableArray,需不需要添加__block

    如果是对数组内修改不需要。如果是修改数组本身,则需要。

    block中访问的外部变量是复制过去的,即: 写操作不对原变量生效。但是你可以加上_block来让其写操作生效。

    5、block怎么进行内存管理的

    自身:_Block_copy_Block_release
    捕获变量:_Block_object_assign_Block_object_dispose

    6、block可以用strong修饰吗

    可以,与copy一样。修饰为copy后会对block里面的对象retain一次,防止里面的对象提前释放。

    7、block循环引用,block分配在栈还是堆,什么 情况下block会从栈区复制到堆区?

    NSConcreteStackBlock:只用到外部局部变量、成员属性变量,且没有强指针引用的block都是StackBlockStackBlock的生命周期由系统控制的,一旦返回之后,就被系统销毁了。

    NSConcreteMallocBlock:有强指针引用或copy修饰的成员属性引用的block会被复制一份到堆中成为MallocBlock,没有强指针引用即销毁, 生命周期由程序员控制。

    没有用到外界变量或只用到全局变量、静态变量的blockNSConcreteGlobalBlock, 生命周期从创建到应用程序结束。

    8、使用系统的某些block api (如UIView的block版本写动画时),是否也考虑引用循环问题?

    系统的某些block api中,如UIViewblock版本写动画时不需要考虑。

    9、block的本质是什么?为啥在block里面更改外面变量的值,要给外面的变量加_ block修饰,加_ block修饰的原理是什么?

    block多用于参数传递,代替代理方法, 有多个参数需要传递或者多个代理方法需要实现还是推荐使用代理方法。

    block是一 个0C对象,它的功能是保存代码片段预先准备好代码,并在需要的时候执行。

    六、OC对象

    1、OC对象

    instance对象包含 isa以及成员变量
    object_getClass(instance)获得class对象,其包含isa以及instance方法
    object_getClass(class)获得meta-class对象 ,其包含isa以及类方法

    2、isa 与 superclass

    instance里存的是真实值,classmeta-class则是类的描述信息

    instanceisa指向class
    classisa 指向meta-class
    meta-classisa 指向基类的meta-class

    classsuperclass 指向 父类的 class; 如果没有父类,superclassnil
    meta-classsuperclass 指向父类的meta-calss
    基类的meta-classsuperclass指向 基类的 classNSObject的特殊性

    3、NSString 用什么关键字?为什么

    copy,为了避免数据被污染,比如可变对它进行赋值,如果不是copy,会导致数据变化。

    4、深拷贝和浅拷贝

    是否生成新的对象,即retaincount是增加1,还是创建新的对象。

    5、NSString使用copy关键字,内部是怎么实现的?

    copyWithZone: => 推测内部进行了一次retain

    6、使用NSArray 保存weak对象,会有什么问题?

    没问题、保存到数组时,会进行一次强引用。

    7、被id声明的对象有什么特性?

    id声明的对象具有运行时的特性,即可以指向任意类型的objcetive-c的对象。

    8、常见的object- c的数据类型有那些,和C的基本数据类型有什么 区别?

    object-c 的数据类型有NSStringNSNumberNSArrayNSMutableArrayNSData等等, 这些都是class,创建后便是对象,而C语言的基本数据类型int,只是一定字节的内存空间, 用于存放数值;

    NSInteger是基本数据类型,并不是NSNumber的子类,当然也不是NSObject的子类。NSInteger是基本数据类型Int或者Long的别名,它的区别在于,NSInteger会根据系统是32位还是64位来决定是本身是int还是Long

    9、对于语句NSString* obj = [NSData alloc] init]; obj在编译时和运行时分别是什么类型的对象?

    编译时是NSString的类型; 运行时是NSData类型的对象。

    10、readwrite, readonly, assign, retain, copy, nonatomic各是有什么作用?

    readwrite是可读可写特性;
    readonly是只读特性,只会生成getter方法,不会生成setter方法不希望属性在类外改变
    assign是赋值特性,setter方法将传入参数赋值给实例变量
    retain表示持有特性,setter方法将传入参数先保留,再赋值,传入参数的retaincount会+1;
    copy表示赋值特性,setter方 法将传入对象复制一份; 需要完全一份新的变量时。
    nonatomic 非原子操作,决定编译器生成的setter getter是否是原子操作,atomic表示多线程安全,防止在写未完成的时候被另外一个线程读取,造成数据错误。一般使用nonatomic,访问器只是简单地返回这个值。

    11、#import跟#include又什么区别,@class呢, #import<>跟#import ""又什么区别?

    #importObjective-C导入头文件的关键字,#includeC/C++导 入头文件的关键字。使用#import头文件会自动只导入一次,不会重复导入,相当于#include#pragma once;

    @class则告诉编译器某个类的声明,当执行时,才去查看类的实现文件,可以解决头文件的相互包含问题。

    #import <>用来包含系统的头文件,#import()用来包含用户头文件。

    12、请描述下Objective-C有哪些优缺点?

    Objective-C的优点:
    1、Cateogies;
    3、动态绑定;
    6、不是一个过度复杂的C衍生语言;
    7、 Objective-C与C++可混合编程

    缺点:
    1、不支持命名空间;
    2、不支持运算符重载;
    3、不支持多重继承;
    4、使用动态运行时类型,所有的方法都是函数调用,所以很多编译时优化方法都用不到。

    13、方法和选择器有何不同?

    selector是一个方法的名字,method是 一个组合体,包含了名字和实现。

    14、tableView的重用机制是什么?

    UTTableView通过重用单元格来达到节省内存的目的: 通过为每个单元格指定一个重用标识符(reuse Ienifir),即指定了单元格的种类以及当单元格滚出屏幕时,允许恢复单元格以便重用对于不同种类的单元格使用不同的ID,对于简单的表格一个标识符就够了。

    假如一个TableView中有I0个单元格,但是屏幕上最多能显示4个,那么实际上iPhone只是为其分配了4个单元格的内存没有分配10个,当滚动单元格时,屏幕内显示的单元格重复使用这4个内存。

    15、Objective C类方法loadView和initialize的区别?

    loadView是只要类所在文件被引用就会被调用,而initialize是在 类或者其子类的第一个方法被调用前调用。所以如果类没有被引用进项目,就不会有load调用; 但即使类文件被引用进来,但是没有使用,那么initialize也不会被调用。

    它们的相同点在于:方法只会被调用一次。
    调用的顺序: 父类(Superclass)的方法优先于子类(SubClass)的方法,类中的方法优先于类别(Category)中的方法。

    16、 @synthesize和@dynamic分别有什么作用?

    @property 有两个对应的词, 一个是@synthesize,一个是@dynamic
    @synthesize的语义是如果你没有手动实现setter方法和getter方法,那么编译器会自动为你加上这两个方法。

    @dynamic告诉编译器:属性的settergetter方法由用户自己实现,不自动生成(当然对于readonly的属性只需提供getter即可)。假如一个属性被声明为@dynamic var,然后你没有提供@setter方法和@getter方法编译的时候没问题,但是当程序运行到instance.var = someVar,由于缺setter方法会导致程序崩溃;或者当运行到someVar = instance.var时,由于缺getter方法同样会导致崩溃。编译时没问题,运行时才执行相应的方法,这就是所谓的动态绑定。

    17、在一个对象的方法里面:self.name =“object";和name =”object"有什么不同吗?

    self.name = "object"会调用对象的setName方法,会使object引用计数加1,
    name = "object"会直接把object赋值给当前对象的name属性,引用计数不增加。

    18、怎么用copy关键字?

    NSStringNSArrayNSDictionary等等经常使用copy关键字,是因为他们有对应的可变类型: NSMutableStringNSMutableArrayNSMutableDictionary

    当属性类型为NSString时,经常用此特质来保护其封装性,因为传递给设置方法的新值有可能指向一个NSMutableString类的实例。这个类是NSStrng的子类,表示一种可修改其值的字符串,此时若是不拷贝字符串,那么设置完属性之后,字符串的值就可能会在对象不知情的情况下遭人更改。

    @property (copy) NSMutableArray *array;这个写法会出什么问题?
    添加, 删除,修改数组内的元素的时候程序会因为找不到对应的方法而崩溃,因为copy就是复制一个不可变NSArray的对象;

    block也经常使用copy关键字, block使用copy是从MRC遗留下来的“传统;
    MRC中,方法内部的block是在栈区的,使用copy可以把它放到堆区
    ARC中写不写都行: 对于block使用copy还是strong效果是一样的, 但写上copy也无伤大雅,还能时刻提醒我们编译器自动对block进行了copy 操作。

    19、objc中向一个nil对 象发送消息将会发生什么?

    Objective-C中向nil发送消息是完全有效的,只是在运行时不会有任何作用:
    如果一个方法返回值是一个对象, 那么发送给nil的消息将返回0(nil)
    objc是动态语言,每个方法在运行时会被动态转为消息发送,即:objc_ msgSend(receiver, selector)

    20、objc中的类方法和实例方法有什么本质区别和联系?

    类方法:
    类方法是属于类对象的
    类方法只能通过类对象调用
    类方法中的self是类对象
    类方法可以调用其他的类方法
    类方法中不能访问成员变量
    类方法中不能直接调用对象方法

    实例方法:
    实例方法是属于实例对象的
    实例方法只能通过实例对象调用.
    实例方法中的self是实例对象
    实例方法中可以访问成员变量
    实例方法中直接调用实例方法
    实例方法中也可以调用类方法(通过类名)

    21、使用nonatomic一定是线程安全的吗?

    不是的。atormic原子操作,系统会为setter方法加锁。具体使用@synchronized(self) {/code }nonatomic不会为setter方法加锁。atomic:线程安全,需要消耗大量系统资源来为属性加锁。

    22、什么是谓词?

    谓词是通过NSPredicate, 是通过给定的逻辑条件作为约束条件,完成对数据的筛选。

    23、isEquel和hash的关系

    isEquel 用于比较2个对象是否相等,与==(地址比较)不一样, 可以重写isEquel方法来进行2个对象的比较。
    hash 是一个类方法,任何类都可以调用这个方法,返回的结果是一个NSInteger值(如果两个对象相等,那么他们的hash值一定相等,但是如果两个对象的哈希值相等是不能一定推出来这两个对象是相等的)

    24、isEquel 和 isEquelToString

    isEquel 比较的是2个NSObject的方法,isEquelToString是比较2个字符串值是否相等。isEquel 首先比较2个对象地址,如果相同就返回YES,如果不同就比较对象类型以及属性的值,一般重写isEquel来比较2个对象。


    七、Category

    见下文 IOS面试:基础题库(下)

    相关文章

      网友评论

        本文标题:IOS面试:基础题库(上)

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