美文网首页
iOS基础知识小记

iOS基础知识小记

作者: 轰炸机上调鸡尾酒 | 来源:发表于2017-11-02 11:30 被阅读23次

    1.swift中遍历删除指定的子数组 ?

    func removeElements(from array: [ExtraTagObject]) {
            var tmp = [Int]()
            for (index, item) in emptyTags.enumerated() {
                for tag in array where tag.tagId == item.tagId {
                    tmp.append(index)
                }
            }
            emptyTags.removeSubrange(tmp.startIndex ..< tmp.endIndex)
     }
    

    注意startIndex和endIndex的使用。

    2.进程间的通信方式?

    • 管道(pipe): 管道是一种半双工的通信方式,数据只能单向流动,而且只能在具有亲缘关系的进程间使用。进程的亲缘关系通常是父子关系。
    • 有名管道(name pipe): 有名管道也是半双工的通信方式,但是它允许无亲缘关系进程间的通信。
    • 信号量(semophore): 信号量是一个计数器,可以用来控制多个进程对共享资源的访问。他可以作为一种锁机制,防止某进程正在访问共享资源时,其他进程也访问该资源。因此,主要作为进程间以及同一进程内不同线程之间的同步手段。
    • 消息队列(message queue):消息队列是由消息的链表,存放在内核中并由消息队列标识符标识。消息队列克服了信号传递信息少,管道只能承载无格式字节流以及缓冲区大小受限等缺点。
    • 信号(singal):信号是比较复杂的通信方式,用于通知接受进程某个事件发生。
    • 共享内存(shared memory): 共享内存就是映射一段能被其他进程所访问的内存,这段共享内存由一个进程创建,但多个进程都可以访问。共享内存是最快的IPC方式,它是针对其他进程通信方式运行效率低而专门设计的。它往往与其他的通信机制,如信号量,配合使用,来实现进程间的同步和通信。
    • 套接字(sokcket): 套接字也是一种进程间的通信机制,与其他通信机制不同的是,它可用于不同主机间的通信。

    3.简述socket流程

    服务端先初始化Socket,然后与端口绑定(bind),对端口进行监听(listen),调用accept阻塞,等待客户端连接。在这时如果有客户端初始化一个clientSocket,然后连接服务器,如果连接成功,这时客户端与服务端的连接就建立了。客户端发送数据请求,服务端接受请求并处理请求,然后把回应数据发送给客户端,客户端读取数据,最后关闭连接,一次交互结束。

    4.table性能优化方面会主要是卡顿和掉帧,这两者有什么区别?
    5.什么是NSTagPointString?
    6.imageNamed有什么弊端,他是什么时候释放的?

    7.iOS事件传递的顺序是怎么样的?
    产生触摸事件 -> UIApplication事件队列 -> [UIWindow hitTestEvent:] ->返回合适的view -> [子控件的 hitTestEvent:] -> 返回最合适的view。
    其中寻找最合适的view的两个重要的方法:hitTest:withEvent:pointInside

    • hitTest:withEvent:
      只要事件一传递给一个控件,这个控件就会调用他自己的hitTest: withEvent去寻找并返回能够响应事件的那个最合适的view。
      注意 除非是事先拦截,不管子控件是不是最合适的view,系统都要先把事件传递给子控件,经过子控件调用自己的hitTest:withEvent:方法验证后才知道有没有更合适的view。
    如果hitTest:withEvent:方法中返回nil,那么调用该方法控件本身和其子控件都不是最合适的view,最合适的view是该空间的父控件。
    
    • 拦截hitTest:withEvent:

      • 因为hitTest: withEvent:方法可以返回最合适的view,所以可以通过重
        写hitTest:withEvent:方法,返回指定的view作为最合适的view。
      • 不管点击哪里,最合适的view都是hitTest:WithEvent:方法中返回的那个view
      • 通过重写hitTest: withEvent:可以拦截事件的传递过程,想让谁处理事件就让谁处理事件。
      • 如果重写window的hitTest:withEvent:方法return nil,那么谁都不能处理事件,窗口也不能处理。
      • 控制器的view和hitTest: WithEvent:方法 return nil 或者 window的hitTest: withEvent:方法返回self,则只能有window才能处理事件。
    • pointInside:withEvent:
      pointInside:withEvent:方法判断点在不在当前的view上。如果返回YES,代表点在方法调用者的坐标系上;返回NO代表点不在方法调用者的坐标系上,那么方法调用者也就不能处理事件。

    • hitTest:withEvent方法的底层会调用pointInside:withEvent:判断点在不在当前view的坐标系上。

    • 拦截这个方法还可以用来修改button的响应热区。
      参考文章

    8.iOS事件的响应链顺序又是怎么样的?

    iOS中响应者链的关系可以用下图表示:


    响应链传递.png
    • 响应者对象
      能处理事件的对象,也就是继承自UIResponder。iOS中只有UIApplication、UIViewController、UIView这三个对象能接受并处理事件。

    • 如何判断上一个响应者

      • 如果当前这个view是控制器的view,那么控制器就是上一个响应者。
      • 如果当前这个view不是控制器的view,那么父控件就是上一个响应者。
    • 响应链的传递过程:

      • 1.如果当前view是控制器的view,那么控制器就是上一个响应者,事件就传递就传递给控制器;如果当前view不是控制器的view,那么父视图就是当前view的上一个响应者,响应就传递给它的父视图。
      • 2.视图层次的最顶级视图,如果也不能处理收到的响应事件,则将时间传递给window对象进行处理。
      • 3.如果window对象也不加处理,则将响应事件或消息传递给UIApplication对象
      • 4.如果UIApplication对象也不能处理该事件或消息,则将其丢弃。
    • 总结: iOS事件处理的整个大流程分两步:1.找到最合适的view,2.将响应链往上传递

      • 1.触摸屏幕产生触摸事件后,触摸事件会被添加到UIApplication管理的事件队列中(即首先接受到事件的是UIApplication)。
      • 2.UIApplication会从事件队列取出最前面的事件,把事件传递给应用程序的主窗口keyWindow。keyWindow是指定的用来接收键盘以及非触摸类的消息,而且程序中每一个时刻只能有一个window是keyWindow.
      • 3.主窗口会在视图层次结构找到一个最合适的视图来处理触摸事件。(至此,第一步已经完成)
      • 4.最合适的view会调用自己的touches方法处理事件。
      • 5.touches默认做法是把事件顺着响应者链条向上抛。

    9.iOS开发中的BitCode有什么用?

    Xcode7后,新建项目默认就打开了bitcode设置.而且大部分开发者都被这个突如其来的bitcode功能给坑过导致项目编译失败,而这些因为bitcode而编译失败的的项目都有一个共同点,就是链接了第三方二进制的库或者框架,而这些框架或者库恰好没有包含bitcode的东西(暂且称为东西),从而导致项目编译不成功.所以每当遇到这个情况时候大部分人都是直接设置Xcode关闭bitcode功能,全部不生成bitcode。

    LLVM是目前苹果采用的编译器工具链,Bitcode是LLVM编译器的中间代码的一种编码,LLVM的前端可以理解为C/C++/OC/Swift等编程语言,LLVM的后端可以理解为各个芯片平台上的汇编指令或者可执行机器指令数据,那么,BitCode就是位于这两者直接的中间码. LLVM的编译工作原理是前端负责把项目程序源代码翻译成Bitcode中间码,然后再根据不同目标机器芯片平台转换为相应的汇编指令以及翻译为机器码.这样设计就可以让LLVM成为了一个编译器架构,可以轻而易举的在LLVM架构之上发明新的语言(前端),以及在LLVM架构下面支持新的CPU(后端)指令输出,虽然Bitcode仅仅只是一个中间码不能在任何平台上运行,但是它可以转化为任何被支持的CPU架构,包括现在还没被发明的CPU架构,也就是说现在打开Bitcode功能提交一个App到应用商店,以后如果苹果新出了一款手机并CPU也是全新设计的,在苹果后台服务器一样可以从这个App的Bitcode开始编译转化为新CPU上的可执行程序,可供新手机用户下载运行这个App.

    LLVM提供了一个虚拟指令集机制,它可以翻译出指定的所支持的处理器架构的执行代码(机器码).这个就使得为iOS应用程序的编译开发一个完全基于LLVM架构的工具链成为可能.而LLVM的这个虚拟的通用的指令集可以用很多种表示格式:

    • 叫做IR的文本表示的汇编格式(像汇编语言);
    • 转换为二进制数据表示的格式(像目标代码),这个二进制格式就是我们所说的bitcode.

    Bitcode和传统的可执行指令集不同,他维护的是函数功能的类型和签名,比如,传统可执行指令集中,一系列(<=8)的布尔值可以压缩存储到单个字节中,但是在bitcode中他们是各自独自表示的.此外,逻辑运算操作(比如寄存器清零操作)也由他们对应的逻辑表示方法($R=0);当这些BitCode要转换为特定机器平台的指令集时,他可以用经过针对特定机器平台优化过的汇编指令来代替:xor eax, eax.(这个汇编指令同样是寄存器<eax>清零操作).

    苹果默认要求watchOS和tvOS的App要上传bitcode? 因为把bitcode上传到他自己的中心服务器后,他可以为目标安装App的设备进行优化二进制,减小安装包的下载大小,当然iOS开发者也可以上传多个版本而不是打包到单个包里,但是这样会占用更多的存储空间. 最重要的是允许苹果可以在后台服务器对应用程序进行签名,而不用导出任何密钥到终端开发者那.

    上传到服务器的bitcode给苹果带来更好处是: 以后新设计了新指令集的新CPU,可以继续从这份bitcode开始编译出新CPU上执行的可执行文件,以供用户下载安装.
    但是bitcode给开发者带来的不便之处就是: 没用bitcode之前,当应用程序奔溃后,开发者可以根据获取的的奔溃日志再配上上传到苹果服务器的二进制文件的调试符号表信息可以还原程序运行过程到奔溃时后调用栈信息,对问题进行定位排查.但是用了bitcode之后,用户安装的二进制不是开发者这边生成的,而是苹果服务器经过优化后生成的,其对应的调试符号信息丢失了,也就无法进行前面说的还原奔溃现场找原因了.

    目前,watchOS和tvOS应用发布必须上传带bitcode版本的包.iOS应用发布对bitcode的要求是可选的,用户可以在Xcode的项目设置中关闭. 相当于在编译的时候加一个标记:embed-bitcode-marker(调试构建) embed-bitcode(打包/真机构建).这个在clang编译器的参数是-fembed-bitcode,swift编译器的参数是-embed-bitcode.

    相关文章

      网友评论

          本文标题:iOS基础知识小记

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