面试题

作者: 1剑天下 | 来源:发表于2020-03-06 16:19 被阅读0次

    https://www.jianshu.com/p/7c44c3b2a056

    一.@property声明的 NSString / NSArray / NSDictionary 经常使用 copy 关键字,为什么?如果改用strong关键字,可能造成什么问题?

    答:使用 copy 的目的是为了让本对象的属性不受外界影响,使用 copy 无论给我传入是一个可变对象还是不可对象,我本身持有的就是一个不可变的副本。如果我们使用是 strong ,那么这个属性就有可能指向一个可变对象,如果这个可变对象在外部被修改了,那么会影响该属性。block 使用 copy 是从 MRC 遗留下来的“传统”,在 MRC 中,方法内部的 block 是在栈区的,使用 copy 可以把它放到堆区.在 ARC 中写不写都行:对于 block 使用 copy 还是 strong 效果是一样的,但写上 copy 也无伤大雅,还能时刻提醒我们:编译器自动对 block 进行了 copy 操作。如果不写 copy ,该类的调用者有可能会忘记或者根本不知道“编译器会自动对 block 进行了 copy 操作”,他们有可能会在调用之前自行拷贝属性值。这种操作多余而低效。

    v二.ViewController生命周期

    按照执行顺序排列:

    initWithCoder:通过nib文件初始化时触发。
    awakeFromNib:nib文件被加载的时候,会发生一个awakeFromNib的消息到nib文件中的每个对象。
    loadView:开始加载视图控制器自带的view。
    viewDidLoad:视图控制器的view被加载完成。
    viewWillAppear:视图控制器的view将要显示在window上。
    updateViewConstraints:视图控制器的view开始更新AutoLayout约束。
    viewWillLayoutSubviews:视图控制器的view将要更新内容视图的位置。
    viewDidLayoutSubviews:视图控制器的view已经更新视图的位置。
    viewDidAppear:视图控制器的view已经展示到window上。
    viewWillDisappear:视图控制器的view将要从window上消失。
    viewDidDisappear:视图控制器的view已经从window上消失。

    三,反射机制

    1.通过类名的字符串形式实例化对象。(NSClassFromString)

    1. 将类名变为字符串。NSString className = NSStringFromClass(class);
      3.通过方法的字符串形式实例化方法。SEL selector = NSSelectorFromString(@"setName");
      4.将方法变成字符串。NSStringFromSelector(@selector(setName:));

    四,runtime

    runtime是oc的底层,一套语言的api,用runtime获取某个类的所有属性(私有属性、非私有属性),在获取到某个类的属性后就可以对该属性进行访问以及修改了。.runtime常用的有:
    1.给分类添加属性
    objc_setAssociatedObject objc_getAssociatedObject
    2.方法交换 比方说 给image加载图片添加一个成功失败啥的

    + (void)load {
        //1,先获取imageNamed方法地址
        // class_getClassMethod(获取某个类的方法)
        Method imageNamedMethod = class_getClassMethod(self, @selector(imageNamed:));
        // 2. 获取自定义的my_imageNamed方法地址
        Method my_imageNamedMethod = class_getClassMethod(self, @selector(my_imageNamed:));
        // 3. 交换方法地址, 相当于交换实现
        method_exchangeImplementations(imageNamedMethod, my_imageNamedMethod);
    }
    

    3.消息转发
    4.反射机制(解偶)

    五。什么闭包

    闭包就是获取其它函数局部变量的匿名函数。
    如果需要在block内部改变外部栈区变量的话,需要在用__block修饰外部变量。

    六,浅拷贝深拷贝

    浅拷贝就是拷贝后,并没有进行真正的复制,而是复制的对象和原对象都指向同一个地址
    深拷贝是值拷贝,生成一个新的对象指向不同的地址
    copy:对于不可变对象为浅拷贝, 对于可变对象为深拷贝,
    mutableCopy:始终是深拷贝

    七 RunLoop

    RunLoop是一种运行循环机制,其实就是死循环。它有两个作用:1.保证程序不退出 2.负
    责监听事件。我们可以理解为Runloop在不断的循环中,一直在询问线程队列中是否有待办任务。如果有任务就去处理,没有任务就休息。
    内部其实是一个do while循环,这也正是Runloop运行的本质

    Thread默认是没有对应的RunLoop的,仅当主动调用Get方法时,才会创建
    所有Thread线程对应的RunLoop被存储在全局的__CFRunLoops字典中。同时,主线程在static CFRunLoopRef __main,子线程在TSD中,也存储了线程对应的RunLoop,用于快速查找。


    image.png

    需要使用port或input source和别的线程通信(基本用不到)
    在当前线程需要使用NSTimer
    在Cocoa程序中需要使用performSelector… 系列函数
    需要子线程保活来执行后台任务
    @autoreleasepool {
    }

    RunLoop的Mode

    关于Mode首先要知道一个RunLoop 对象中可能包含多个Mode,且每次调用 RunLoop 的主函数时,只能指定其中一个 Mode(CurrentMode)。切换 Mode,需要重新指定一个 Mode 。主要是为了分隔开不同的 Source、Timer、Observer,让它们之间互不影响。

    image.png

    八 Cocoapods 的工作流程

    • 查看 ~/.cocoapods/repo/master/Specs 是否存在
    • 存在,从这个本地三方库信息库中获取 Podfile 中对应三方库的 git 地址
    • 不存在,输出 Setting up CocoaPods Master repo,并拉取三方库信息库到 ~/.cocoapods/repo/中* 使用 git 命令从 GitHub 上拉取 Podfile 中对应的三方库源码

    九 响应者链

    响应者链就是通过UIResPonder的属性链接起来的view和controller,但一个view添加到他的父试图上时,他的nextUIResPonder就指向他的父视图,形成一条链

    十 点击发生了什么

    1.当iOS程序发生触摸事件后,系统会利用Runloop将事件加入到UIApplication的任务队列中
    2.UIApplication分发触摸事件到UIWindow,然后UIWindow依次向下分发给UIView
    3.UIView调用hitTest:withEvent:方法看看自己能否处理事件,以及触摸点是否在自己上面。
    4.如果满足条件,就遍历UIView上的子控件。重复上面的动作。直到找到最顶层的一个满足条件

    十一 hitTest:withEvent:的处理流程

    1.首先调用当前视图的pointInside:withEvent:方法判断触摸点是否在当前视图内;
    2.若返回NO,则hitTest:withEvent:返回nil;
    3.若返回YES,则向当前视图的所有子视图(subviews)发送hitTest:withEvent:消息,所有子视图的遍历顺序是从最顶层视图一直到到最底层视图,即从subviews数组的末尾向前遍历,直到有子视图返回非空对象或者全部子视图遍历完毕
    4.若第一次有子视图返回非空对象,则hitTest:withEvent:方法返回此对象,处理结束;
    5.如所有子视图都返回非,则hitTest:withEvent:方法返回自身(self)。

    十二 UIView为CALayer提供内容,以及负责处理触摸等事件,参与响应链
    CALayer负责显示内容contents

    十三 view和layer
    UIView为CALayer提供内容,以及负责处理触摸等事件,参与响应链
    CALayer负责显示内容contents

    十四 图像显示原理
    的图像经过CRT电子枪以极快的速度一行一行的扫描,扫描出来就呈现了一帧画面,随后电子枪又会回到初始位置循环扫描,形成了我们看到的图片或视频。为了让显示器的显示跟视频控制器同步,当电子枪新扫描一行的时候,准备扫描的时发送一个水平同步信号(HSync信号),显示器的刷新频率就是HSync信号产生的频率。然后CPU计算好frame等属性,将计算好的内容交给GPU去渲染,GPU渲染好之后就会放入帧缓冲区。然后视频控制器会按照HSync信号逐行读取帧缓冲区的数据,经过可能的数模转换传递给显示器,就显示出来了。这里只是简作描述,专业描述请自行查询

    1.CPU:输出位图
    2.GPU :图层渲染,纹理合成
    3.把结果放到帧缓冲区(frame buffer)中
    4.再由视频控制器根据vsync信号在指定时间之前去提取帧缓冲区的屏幕显示内容
    5.显示到屏幕上

    十四 CPU工作
    1.Layout: UI布局,文本计算
    2.Display: 绘制
    3.Prepare: 图片解码
    4.Commit:提交位图

    十五 UI卡顿掉帧原因

    CPU会去计算屏幕要显示的内容,之后将计算好的内容提交到GPU去渲染。随后,GPU将渲染结果提交到帧缓冲区,等到下一个VSync到来时将缓冲区的帧显示到屏幕上。一帧的显示是由CPU和GPU共同决定的。一般来说,页面滑动流畅是60fps,也就是1s有60帧更新,即每隔16.7ms就要产生一帧画面,而如果CPU和GPU加起来的处理时间超过了16.7ms,就会造成掉帧甚至卡顿。
    滑动优化方案
    CPU:把以下操作放在子线程中
    1.对象创建、调整、销毁
    2.预排版(布局计算、文本计算、缓存高度等等)
    3.预渲染(文本等异步绘制,图片解码等)

    十六 离屏渲染
    GPU屏幕渲染有两种方式:

    (1)On-Screen Rendering (当前屏幕渲染)

    指的是GPU的渲染操作是在当前用于显示的屏幕缓冲区进行。

    (2)Off-Screen Rendering (离屏渲染)
    指的是在GPU在当前屏幕缓冲区以外开辟一个缓冲区进行渲染操作。

    离屏渲染的代价是很高的 创建新缓冲区 上下文切换

    既然离屏渲染这么耗性能,为什么有这套机制呢?

    有些效果被认为不能直接呈现于屏幕,而需要在别的地方做额外的处理预合成。图层属性的混合体没有预合成之前不能直接在屏幕中绘制,所以就需要屏幕外渲染。屏幕外渲染并不意味着软件绘制,但是它意味着图层必须在被显示之前在一个屏幕外上下文中被渲染(不论CPU还是GPU)。

    下面的情况或操作会引发离屏渲染:

    • 为图层设置遮罩(layer.mask)
    • 将图层的layer.masksToBounds / view.clipsToBounds属性设置为true
    • 将图层layer.allowsGroupOpacity属性设置为YES和layer.opacity小于1.0
    • 为图层设置阴影(layer.shadow *)。
    • 为图层设置layer.shouldRasterize=true
    • 具有layer.cornerRadius,layer.edgeAntialiasingMask,layer.allowsEdgeAntialiasing的图层
    • 文本(任何种类,包括UILabel,CATextLayer,Core Text等)。
    • 使用CGContext在drawRect :方法中绘制大部分情况下会导致离屏渲染,甚至仅仅是一个空的实现。
      https://www.jianshu.com/p/cff0d1b3c915

    十七,自动释放池的原理:
    排布在“栈”中,对象执行autorelease消息后,系统将其放入最顶端的池里(进栈),而清空自动释放池就是把对象销毁(出栈)。而调用出栈的时机:就是当前线程执行下一次事件循环时。

    十八 谓词
    NSPredicate类是用来定义逻辑条件约束的获取或内存中的过滤搜索。
    可以使用谓词来表示逻辑条件,用于描述对象持久性存储在内存中的对象过滤。其实意思就是:我是一个过滤器,不符合条件的都滚开。

    十九 Category 为什么不能添加实例变量

    通过结构体 category_t ,我们就可以知道,在 Category 中我们可以增加实例方法、类方法、协议、属性。这里没有 objc_ivar_list 结构体,代表我们不可以在分类中添加实例变量。

    因为在运行期,对象的内存布局已经确定,如果添加实例变量就会破坏类的内部布局,这个就是 Category 中不能添加实例变量的根本原因。

    相关文章

      网友评论

          本文标题:面试题

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