面试日记_2020-10-21

2020-10-22  本文已影响0人  Hengry

iOS面试题 - Swift语言

【千聊】
一. open、public的区别?
private、fileprivate、internal、public和open的区别

二. Swift中struct、class的区别?
Swift中enum、struct、class三者异同

三. Swift中Optional实现原理?
可选型Optional

四. Swift什么情况使用final?

五. assign和weak底层实现原理?

六. category(类别)、extension(拓展)、继承的区别?
iOS分类(category)、类扩展(extension)、继承的区别

七. KVO实现原理?
IOS底层(三) KVO底层实现原理

八. 下面代码执行结果如何?

    NSLog(@"1");
    dispatch_sync(dispatch_get_main_queue(), ^{
        NSLog(@"2");
    });
    NSLog(@"3");
  // 打印:1;然后线程发生异常,出现卡死现象。线程相互等待对方任务执行完毕导致卡死现象.

九. 冒泡排序最坏时间复杂度是多少?【O(n^2)】
冒泡排序、插入排序、选择排序时间复杂度都是O(n2)

【维梦科技】
一. Swift的优点?缺点?
Swift相比OC语言有哪些优点

二、assign和weak的区别?

ARC:才有weak
weak:__weak 弱指针,不会让引用计数器+1,如果指向对象被销毁,指针会自动清空
assgin:__unsafe_unretained修饰,不会让引用计数器+1,如果指向对象被销毁,指针不会清空
解析2

三、如何实现监听屏幕帧率?
关于CADisplayLink的描述有两种

CADisplayLink 是一个和屏幕刷新率一致的定时器(但实际实现原理更复杂,和 NSTimer 并不一样,其内部实际是操作了一个 Source)。如果在两次屏幕刷新之间执行了一个长任务,那其中就会有一帧被跳过去(和 NSTimer 相似),造成界面卡顿的感觉。在快速滑动TableView时,即使一帧的卡顿也会让用户有所察觉。

CADisplayLink是一个执行频率(fps)和屏幕刷新相同(可以修改preferredFramesPerSecond改变刷新频率)的定时器,它也需要加入到RunLoop才能执行。与NSTimer类似,CADisplayLink同样是基于CFRunloopTimerRef实现,底层使用mk_timer(可以比较加入到RunLoop前后RunLoop中timer的变化)。和NSTimer相比它精度更高(尽管NSTimer也可以修改精度),不过和NStimer类似的是如果遇到大任务它仍然存在丢帧现象。通常情况下CADisaplayLink用于构建帧动画,看起来相对更加流畅,而NSTimer则有更广泛的用处。

不管怎么样CADisplayLink和NSTimer是有很大不同的,详情可以参考这篇文章CADisplayLink

ibireme根据CADisplayLink的特性写了个FPS指示器YYFPSLabel,代码非常少
原理是这样的:既然CADisplayLink可以以屏幕刷新的频率调用指定selector,而且iOS系统中正常的屏幕刷新率为60Hz(60次每秒),所以使用 CADisplayLink 的 timestamp 属性,配合 timer 的执行次数计算得出FPS数

作者:小凉介
链接:https://www.jianshu.com/p/f33c0e5ad0e2
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

【中软国际】
一、冒泡排序(上机题 )
Swift-冒泡排序、快速排序、归并排序、二分查找

    func testExample() throws {
        // This is an example of a functional test case.
        // Use XCTAssert and related functions to verify your tests produce the correct results.
        
        let array: [Int] = [23, 523, 11, 98, 1, 54, 83, 22]
        let result = bubbleSort(array)
        for a in result {
            print(a);
        }
    }
    
    func bubbleSort(_ array:[Int]) -> [Int]{
      var sortArr:[Int] = array
      for i in 0..<sortArr.count {
          for j in i+1..<sortArr.count {
              if sortArr[i] > sortArr[j] {
                  sortArr.swapAt(i, j)
              }
          }
      }
      return sortArr
    }

【爱拍】
1、什么是dSYM文件?
dSYM文件
收集崩溃信息

2、常用第三方库原理:AFN、SDWebImage
AFNetworking的漂亮细节
AFNetworking到底做了什么?(一)
AFNetworking到底做了什么?(二)
AFNetworking之于https认证

3、SDWebImage
SDWebImage源码解析(一)——WebCache+Manager模块
SDWebImage源码解析(二)——SDImageCache缓存模块
SDWebImage源码解析(三)——SDWebImage图片解码/压缩模块
SDWebImage源码解析(四)——SDWebImage图片下载模块
SDWebImage深度剖析

4、一个 NSObject 对象占用多少内存空间?
一个 NSObject 对象占用16字
一个OC对象占用多少内存?

【YY】
1、webp配置
ios项目支持webp图片格式

2、runtime底层原理

3、异步线程如何控制确保数据读写安全。
GCD信号量-dispatch_semaphore_t
利用dispatch_semaphore信号旗来控制线程安全操作数据.
dispatch_semaphore_create
dispatch_semaphore_wait
dispatch_semaphore_signal

4、自旋锁和互斥锁的区别?
自旋锁和互斥锁的区别

5、常用设计模式

6、项目架构:mvc、mvvm、mvp

7、如何检测卡顿
iOS卡顿优化方案
iOS界面流畅之卡顿产生的原因和解决方案

8、启动性能优化
iOS开发-性能优化-启动优化

9、性能优化
iOS性能优化

【声网】
1、runtime实现原理,消息转发机制
runtime底层实现原理
用runtime看OC中类与对象,消息的底层实现原理

2、KVO/KVC
KVC/KVO实现原理

3、HandyJSON实现思路
HandyJSON 设计思路简析

4、RxSwift中冷信号、热信号有什么区别?
RxSwift-冷信号和热信号

热信号

热信号在订阅期间不会产生任何副作用,但是它确实存在自己的上下文,这些事件都是在自己的上下文环境中生成的,并且RxSwift并不能控制它(也就是说,它在自己的线程中运行)
热信号可以随时发送元素,如果观察者在其开始发送元素之后才开始订阅,那么会错过先前发送的所有元素
冷信号

冷信号在其他观察者订阅之前是不会生成任何元素的。这意味着它在订阅之前是没有自己的上下文环境的,当订阅发生之后,它会创建某个上下文环境并且开始生成元素
冷信号只有在有观察者进行订阅之后才发送元素
冷热信号的区分可以简化成一个简单的问题:在订阅的时候是否存在副作用?
是否存在副作用可以转换成,副作用是否是共享的?
如果副作用只是在订阅之后才执行的,那么这个副作用就是不共享的;
反之,这个副作用就是共享的

冷热信号的对比
热信号:

无论是否存在订阅者都会使用资源
无论是否存在订阅者都会生成元素
主要跟BehaviorSubject这类状态类型一起使用
冷信号:

只有在订阅生成之后才消耗资源
只有有订阅者的时候才会生成元素
主要用于异步操作,比如网络请求

【网易一面】
1、assign、weak区别?weak底层实现原理?

2、copy、mutablecopy区别? 可变数组执行mutablecopy操作,数组中的元素是深度拷贝吗?
【解析】
只有不可变对象进行mopy操作是浅拷贝,其余情况都是深拷贝;
可变数组mutablecopy是深拷贝,但是数组中的元素是浅拷贝(指针拷贝).

- (void)test1Example {

    NSMutableArray *arr = [[NSMutableArray alloc] initWithObjects:@"1", @"2", nil];
    NSMutableArray *arr2 = [arr mutableCopy];
    NSObject *obj1 = [arr objectAtIndex:0];
    NSObject *obj2 = [arr2 objectAtIndex:0];
    NSLog(@"\n%p\n%p", arr, arr2);
    NSLog(@"+++++++++++++");
    NSLog(@"\n%p\n%p", obj1, obj2);
}

2020-11-08 10:40:16.026207+0800 OCTest[40991:4888017] 
0x600002d56df0
0x600002d56e80
2020-11-08 10:40:16.026365+0800 OCTest[40991:4888017] +++++++++++++
0x102966080
0x102966080

3、线程卡死问题

    NSLog(@"1");
    NSLog(@"2");
    NSLog(@"3");
    dispatch_sync(dispatch_get_main_queue(), ^{
        NSLog(@"4");
    });
    NSLog(@"5");

4、同步执行

    NSLog(@"1");
    NSLog(@"2");
    NSLog(@"3");
    dispatch_sync(dispatch_get_global_queue(0, 0), ^{
        NSLog(@"4");
    });
    NSLog(@"5");

2020-11-12 22:14:01.314141+0800 OCTest[50753:6640569] 1
2020-11-12 22:14:01.314352+0800 OCTest[50753:6640569] 2
2020-11-12 22:14:01.314456+0800 OCTest[50753:6640569] 3
2020-11-12 22:14:01.314555+0800 OCTest[50753:6640569] 4
2020-11-12 22:14:01.314643+0800 OCTest[50753:6640569] 5

5、苹果内购流程以及丢单问题

6、多线程如何控制多读单写?

7、响应链的流程
事件传递和响应机制

8、KVO实现原理

9、多个分类实现同一个方向,如何调用问题
多个category实现同一个方法调用的顺序
根据编译的顺序,只调用最后编译的分类方法.

10、https认证流程

11、Http、Tcp的理解

12、Tcp三层握手、四次挥手流程?为什么不是2次握手呢?

【今日头条】一面
1、#import<>和#import""的区别
#import、#include、@class、#import<>和#import""的区别

<>: 引用系统文件,它用于对系统自带的头文件的引用,编译器会在系统文件目录下去查找该文件。
"": 用户自定义的文件用双引号引用,编译器首先会在用户目录下查找,然后到安装目录中查。

2、frame、bounds区别? 旋转View的情况下,frame和bounds是否会变化?
旋转的情况下frame会变,bounds不会变

3、同一线程执行异步任务顺序

    func testGCD() {
// 主线程异步执行任务,异步任务先进先出        
        DispatchQueue.main.async {
            DispatchQueue.main.async {
                sleep(5)
                print("-->1")
            }
            print("-->2")
            DispatchQueue.main.async {
                print("-->3")
            }
        }
    }

打印结果:
-->2
-->1
-->3

【算法题】
一、对称二叉树

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution {
public:
    bool isMirro(TreeNode *t1, TreeNode *t2){

        if(t1 == NULL && t2 == NULL){
            return true;
        }
        
        if(t1 == NULL || t2 == NULL){
            return false;
        }

        return (t1->val == t2->val) && isMirro(t1->left, t2->right) && isMirro(t1->right, t2->left);
    }

    bool isSymmetric(TreeNode* root) {
        return isMirro(root, root);
    }
};

【重点知识点】
IOS中weak的底层实现原理?
Runtime会维护一个weak表,用于维护指向对象的所有weak指针。weak表是一个哈希表,其key为所指对象的指针,value为weak指针的地址数组。
具体过程如下:

1、初始化时:runtime会调用objc_initWeak函数,初始化一个新的weak指针指向对象的地址。
2、添加引用时:objc_initWeak函数会调用 objc_storeWeak() 函数,更新指针指向,创建对应的弱引用表。
3、释放时,调用clearDeallocating函数。clearDeallocating函数首先根据对象地址获取所有weak指针地址的数组,然后遍历这个数组把其中的数据设为nil,最后把这个entry从weak表中删除,最后清理对象的记录。


iOS alloc方法中做了什么?
核心三步:
1.计算对象所有属性所需要 size
2.调用 calloc 开辟足够的空间
3.isa 进行位运算将对象和类关联起来

alloc分配内存并将内存地址返回给指针,init对分配的内存初始化

TCP和UDP的优缺点及区别

面试题收集:
直击2020——iOS 面试题大全(补充完整版)

了解

dyld详解

上一篇下一篇

猜你喜欢

热点阅读