草庐IT

【iOS面试总结】疫情隔离中,线上面试的问题集合(第一部分)

Mr.Xu 2023-03-28 原文

 1、内存管理部分

  1.1 介绍下内存管理机制

  在iOS中,使用引用计数来管理OC对象的内存   

  一个新创建的OC对象引用计数默认是1,当引用计数减为0,OC对象就会销毁,释放其占用的内存空间,调用retain会让OC对象的引用计数+1,调用release会让OC对象的引用计数-1   

  内存管理的经验总结   

  MRC下 :

    当调用alloc、new、copy、mutableCopy方法返回了一个对象,在不需要这个对象时,要调用release或者autorelease来释放它     

    想拥有某个对象,就让它的引用计数+1;不想再拥有某个对象,就让它的引用计数-1     

    可以通过以下私有函数来查看自动释放池的情况     

    extern void _objc_autoreleasePoolPrint(void);   

  ARC下

     LLVM + Runtime 会为我们代码自动插入 retain 和 release 以及 autorelease等代码,不需要我们手动管理

 

  1.2 AutoreleadPool底层结构

    AutoreleasePool并没有单独的结构,而是由若干个AutoreleasePoolPage以双向链表的形式组合而成的栈结构(分别对应结构中的parent指针和child指针)

  1.3 常见的内存泄漏问题

    泄露的内存主要有以下两种:  

      Leak Memory 这种是忘记 Release 操作所泄露的内存。

      Abandon Memory 这种是循环引用,无法释放掉的内存。

    当时我只列出了循环引用引起的内存泄漏问题,欢迎其他补充。

    1.3.1 NSTimer 

      NSTimer会默认对当前self有个强引用,所有在self使用完成打算是否的时候,一定要先使用NSTimer的invalidate来停止是否时间控制对self的引用

    1.3.2 Block

      Block也是比较常见的循环引用问题,在Block中使用了self容易出现循环引用,因此很多人在使用block的时候,加入里面有用到self的操作都会声明一个__weak来修饰self。其实便不是这样的,不是所有使用了Block都会出现Self循环引用问题,只有self拥有Block的强引用才会出现这种情况。

    1.3.3 delegate
      Delegate是ios中开发中最常遇到的循环引用,一般在声明delegate的时候都要使用弱引用weak或者assign

  2、优化部分

   2.1 性能优化

     1、在正确的地方使用 reuseIdentifier :  

        正确使用identifier可以有效复用cell。

     2、避免过于庞大的XIB: 

        当你加载一个引用了图片或者声音资源的nib时,nib加载代码会把图片和声音文件写进内存。

     3、不要阻塞主线程:  

        永远不要使主线程承担过多。因为UIKit在主线程上做所有工作,渲染,管理触摸反应,回应输入等都需要在它上面完成。一直使用主线程的风险就是如果你的代码真的block了主线程,你的app会失去反应,大部分阻碍主进程的情形是你的app在做一些牵涉到读写外部资源的I/O操作,比如存储或者网络。 

     4、在Image Views中调整图片大小: 

        如果要在UIImageView中显示一个来自bundle的图片,你应保证图片的大小和UIImageView的大小相同。在运行中缩放图片是很耗费资源的,特别是UIImageView嵌套在UIScrollView中的情况下。

        如果图片是从远端服务加载的你不能控制图片大小,比如在下载前调整到合适大小的话,你可以在下载完成后,最好是用background thread,缩放一次,然后在UIImageView中使用缩放后的图片。

   2.2 耗电优化

     耗电大户:CPU、网络请求、定位、GPU、多媒体、相机等等。

     2.2.1 网络请求

       1、减少、压缩网络数据。可以降低上传或下载的多媒体内容质量和尺寸等。

       2、使用缓存,不要重复下载相同的数据。

       3、网络不可用时不要尝试执行网络请求。

     2.2.2 定位

       1、除非是在导航的时候,app大部分时间不需要实时更新,降低位置的更新频率。

       2、尽量降低定位精度。iOS设备默认采用最高精度定位,如果你的app不是确实需要米级的位置信息,不要用最高精度

     2.2.3 CPU

        1、尽量减少计时器使用。使用计时器时,设置一个合适的超时时,不再需要时及时关闭重复性定时器。用事件通知代替定时器。有些app用定时器监控文件内容、网络或者其他状态的变化,这会导致CPU无法进入闲置状态而增加功耗。

     2.2.4 优化I/O访问

       1、app每次执行I/O任务,比如写文件,会导致系统退出闲置模式。而且写入缓存格外耗电。

     2.2.5 优化通知

       1、尽量用本地通知(local notification),如果你的app不依赖外部数据,而是需要基于时间的通知,应该用本地通知,可以让设备的网络硬件休息一下。

       2、远程推送有两个级别,一个是立即推送,另一个是针对功耗优化过的延时推送。如果不是真的需要即时推送,尽量使用延时推送。

    2.3 启动优化

      App启动时间可以通过xcode提供的工具来度量,在Xcode的Product->Scheme-->Edit Scheme->Run->Auguments中,将环境变量DYLD_PRINT_STATISTICS设为YES,优化需以下方面入手

      1、核心思想是减少dylibs的引用

      2、合并现有的dylibs(最好是6个以内)

      3、使用静态库

      4、多使用Swift结构体

   2.4 瘦身优化

      降低包大小需要从两方面着手

      2.4.1 编译器优化:

        Strip Linked Product、Make Strings Read-Only、Symbols Hidden by Default 设置为 YES,去掉异常支持,Enable C++ Exceptions、Enable Objective-C Exceptions 设置为 NO, Other C Flags 添加 -fno-exceptions 利用 AppCode 检测未使用的代码:菜单栏 -> Code -> Inspect Code编写LLVM插件检测出重复代码、未被调用的代码

      2.4.2 资源优化:

        1、可以对资源进行无损的压缩

        2、去除没有用到的资源

   3、HTTP / HTTPS

     3.1、TCP/IP中文名字是啥?

        Transmission Control Protocol/Internet Protocol,传输控制协议/网际协议  

     3.2、TCP/IP 四层模型 和OSI七层模型

    

     3.3、HTTP是作用在哪一层?

        应用层

     3.4、HTTPS三次握手

        1、客户端发送SYN包到服务端,等待服务端确认;

        2、服务端确认接收SYN包,并发送回来一个SYN+ACK包给客户端;

        3、客户端确认接收,并向服务端发送确认包ACK,连接建立。

    

   4、Swift部分

     4.1 swift 和 objective-c 区别?

       1、swift是强类型(静态)语言,有类型判断,objective-c弱类型(动态)语言    

       2、swift面向协议编程,objective-c面向对象编程 

       3、swift比objective-c代码简洁

       4、swift注重值类型,objective-c注重引用类型

       5、swift支持静态派发、动态派发方式,objective-c仅支持动态派发方式 

     4.2 什么是可选型(optional)?

       可选型是为了表达一个变量为空的情况,当一个变量为空,它的值就是nil

       在类型名称后面加个?来定义一个可选型

       值类型或引用类型都可以是可选型变量

var name: String? // 默认为 nil
var age: Int?     // 默认为nil
print(name, age) // 打印 nil, nil

     4.3 什么是泛型?        

       泛型是为了增加代码的灵活性而生的,它可以是满足对应代码类型的任意变量或方法;可以将类型参数化,提高代码复用率,减少代码量

func swap<T>(a: inout T, b: inout T) {
    (a, b) = (b, a)
}

     4.4 访问控制关键字

       Swift 中有个5个级别的访问控制权限,从高到低依次是 open, public, internal, fileprivate, private

       它们遵循的基本规则: 高级别的变量不允许被定义为低级别变量的成员变量,比如一个 private 的 class 内部允许包含 public的 String值,反之低级变量可以定义在高级别变量中;

       1、open: 具备最高访问权限,其修饰的类可以和方法,可以在任意 模块中被访问和重写.

       2、public: 权限仅次于 open,和 open 唯一的区别是: 不允许其他模块进行继承、重写

       3、internal: 默认权限, 只允许在当前的模块中访问,可以继承和重写,不允许在其他模块中访问

       4、fileprivate: 修饰的对象只允许在当前的文件中访问;

       5、private: 最低级别访问权限,只允许在定义的作用域内访问

  5、多线程

     5.1 什么是多线程?

        多线程是指实现多个线程并发执行的技术,进而提升整体处理性能。

        同一时间,CPU 只能处理一条线程,多线程并发执行,其实是 CPU 快速的在多条线程之间调度(切换)如果 CPU 调度线程的时间足够快, 就造成了多线程并发执行的假象。

      5.2 使用多线程的优势和弊端?

        优势:充分发挥多核处理器的优势,将不同线程任务分配给不同的处理器,真正进入“并行计算”状态

        弊端:新线程会消耗内存控件和cpu时间,线程太多会降低系统运行性能。

     5.3 进程和多线程的区别?

        进程:正在运行的程序,负责程序的内存分配,每一个进程都有自己独立的虚拟内存空间。(一个程序运行的动态过程)

        线程:线程是进程中一个独立执行的路径(控制单元)一个进程至少包含一条线程,即主线程可以将耗时的执行路径(如网络请求)放在其他线程中执行。

        比较:

          1、线程是 CPU 调用的最小单位

          2、进程是 CPU 分配资源和调度的单位

            3、一个程序可以对应多个进程,一个进程中可有多个线程,但至少要有一条线程

          4、同一个进程内的线程共享进程资源

     5.4 GCD的调度队列有哪些?

        1、主队列(main queue)

          主队列是串行队列。和其它串行队列一样,这个队列中的任务一次只能执行一个。然而,它能保证所有的任务都在主线程执行,而主线程是唯一可用于更新 UI 的线程。这个队列就是用于发生消息给 UIView 或发送通知的。

        2、全局调度队列(Global Dispatch Queues) 

          全局调度队列是并发队列。目前的四个全局队列有着不同的优先级:background、low、default 以及 high。 

        3、自定义队列

          你也可以创建自己的串行队列或并发队列。 

 

   接下文 【iOS面试总结】疫情隔离中,线上面试的问题集合(第二部分)

有关【iOS面试总结】疫情隔离中,线上面试的问题集合(第一部分)的更多相关文章

  1. ruby - 如何验证 IO.copy_stream 是否成功 - 2

    这里有一个很好的答案解释了如何在Ruby中下载文件而不将其加载到内存中:https://stackoverflow.com/a/29743394/4852737require'open-uri'download=open('http://example.com/image.png')IO.copy_stream(download,'~/image.png')我如何验证下载文件的IO.copy_stream调用是否真的成功——这意味着下载的文件与我打算下载的文件完全相同,而不是下载一半的损坏文件?documentation说IO.copy_stream返回它复制的字节数,但是当我还没有下

  2. Ruby 文件 IO 定界符? - 2

    我正在尝试解析一个文本文件,该文件每行包含可变数量的单词和数字,如下所示:foo4.500bar3.001.33foobar如何读取由空格而不是换行符分隔的文件?有什么方法可以设置File("file.txt").foreach方法以使用空格而不是换行符作为分隔符? 最佳答案 接受的答案将slurp文件,这可能是大文本文件的问题。更好的解决方案是IO.foreach.它是惯用的,将按字符流式传输文件:File.foreach(filename,""){|string|putsstring}包含“thisisanexample”结果的

  3. 【Java 面试合集】HashMap中为什么引入红黑树,而不是AVL树呢 - 2

    HashMap中为什么引入红黑树,而不是AVL树呢1.概述开始学习这个知识点之前我们需要知道,在JDK1.8以及之前,针对HashMap有什么不同。JDK1.7的时候,HashMap的底层实现是数组+链表JDK1.8的时候,HashMap的底层实现是数组+链表+红黑树我们要思考一个问题,为什么要从链表转为红黑树呢。首先先让我们了解下链表有什么不好???2.链表上述的截图其实就是链表的结构,我们来看下链表的增删改查的时间复杂度增:因为链表不是线性结构,所以每次添加的时候,只需要移动一个节点,所以可以理解为复杂度是N(1)删:算法时间复杂度跟增保持一致查:既然是非线性结构,所以查询某一个节点的时候

  4. Get https://registry-1.docker.io/v2/: net/http: request canceled while waiting - 2

    1.错误信息:Errorresponsefromdaemon:Gethttps://registry-1.docker.io/v2/:net/http:requestcanceledwhilewaitingforconnection(Client.Timeoutexceededwhileawaitingheaders)或者:Errorresponsefromdaemon:Gethttps://registry-1.docker.io/v2/:net/http:TLShandshaketimeout2.报错原因:docker使用的镜像网址默认为国外,下载容易超时,需要修改成国内镜像地址(首先阿里

  5. SPI接收数据异常问题总结 - 2

    SPI接收数据左移一位问题目录SPI接收数据左移一位问题一、问题描述二、问题分析三、探究原理四、经验总结最近在工作在学习调试SPI的过程中遇到一个问题——接收数据整体向左移了一位(1bit)。SPI数据收发是数据交换,因此接收数据时从第二个字节开始才是有效数据,也就是数据整体向右移一个字节(1byte)。请教前辈之后也没有得到解决,通过在网上查阅前人经验终于解决问题,所以写一个避坑经验总结。实际背景:MCU与一款芯片使用spi通信,MCU作为主机,芯片作为从机。这款芯片采用的是它规定的六线SPI,多了两根线:RDY和INT,这样从机就可以主动请求主机给主机发送数据了。一、问题描述根据从机芯片手

  6. ruby - 为什么不能使用类IO的实例方法noecho? - 2

    print"Enteryourpassword:"pass=STDIN.noecho(&:gets)puts"Yourpasswordis#{pass}!"输出:Enteryourpassword:input.rb:2:in`':undefinedmethod`noecho'for#>(NoMethodError) 最佳答案 一开始require'io/console'后来的Ruby1.9.3 关于ruby-为什么不能使用类IO的实例方法noecho?,我们在StackOverflow上

  7. ruby-on-rails - CarrierWave - PDF - 只选择第一页 - 2

    我的Rails应用程序中安装了carrierwave。但是,当用户上传多页pdf时,我只希望应用程序获取文档中的第一页并将其转换为jpeg。这可能吗?用什么命令?这是我的uploader。#encoding:utf-8classImageUploader[200,300]##defscale(width,height)##dosomething#end#Createdifferentversionsofyouruploadedfiles:version:thumbdoprocess:resize_to_fill=>[150,210]process:convert=>:jpgdefful

  8. ruby - 如何跳过 CSV 文件的第一行并将第二行作为标题 - 2

    有没有办法跳过CSV文件的第一行,让第二行作为标题?我有一个CSV文件,第一行是日期,第二行是标题,所以我需要能够在遍历它时跳过第一行。我尝试使用slice但它会将CSV转换为数组,我真的很想将其读取为CSV,以便我可以利用header。 最佳答案 根据您的数据,您可以使用另一种方法和skip_lines-option此示例跳过所有以#开头的行require'csv'CSV.parse(DATA.read,:col_sep=>';',:headers=>true,:skip_lines=>/^#/#Markcomments!)do|

  9. arrays - 在一行中选择数组的第一个和最后一个元素 - 2

    我的任务是从数组中选择最高和最低的数字。我想我很清楚我想做什么,但只是努力以正确的格式访问信息以满足通过标准。defhigh_and_low(numbers)array=numbers.split("").map!{|x|x.to_i}array.sort!{|a,b|ba}putsarray[0,-1]end数字可能看起来像"80917234100",要通过,我需要输出"9234"。我正在尝试putsarray.first.last,但一直无法弄明白。 最佳答案 有Array#minmax完全满足您需要的方法:array=[80,

  10. ruby-on-rails - Ruby 或 Rails 有只将第一个字符大写的方法吗? - 2

    或者好像我必须自己写方法?(保持DHA不变):ruby-1.9.2-p180:001>s='omega-3(DHA)'=>"omega-3(DHA)"ruby-1.9.2-p180:002>s.capitalize=>"Omega-3(dha)"ruby-1.9.2-p180:003>s.titleize=>"Omega3(Dha)"ruby-1.9.2-p180:005>s[0].upcase+s[1..-1]=>"Omega-3(DHA)" 最佳答案 如果我的回答只是垃圾,我深表歉意(我不做ruby)。但我相信我已经为您找到了答

随机推荐