inverview

/** 事件传递

hidden
userInteractionEabled
alpha > 0.1

  • (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event{

}

  • (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event{

}
*/

@implementation EventView
/** CPU
layout: UI布局, 文本计算
display: 绘制 - drawRect
prepare: 解码
commit: 提交 bitmap

*/

/** GPU 渲染管线

顶点着色
图元装配
光栅化
片段着色
片段处理

-> FrameBuffer
*/

/** 滑动优化方案

  • CPU
    对象的创建, 调整, 销毁放到子线程去操作
    预排版(布局, 文本计算)
    预渲染(文本的异步绘制, 图片编解码)

*GPU
纹理渲染(离屏渲染, maskToBounce, shadow)
视图混合(视图层级复杂性, 合成位图)

*/

/** 异步绘制
判断 -[layer.delegate displayLayer:]
layer的代理遵守了代理,
步骤:
// [self setNeedsDisplay];
// [self.layer setNeedsDisplay];
// [layer.delegate displayLayer:];
--> 切换到子线程, 生成 bitmap
-> 返回主线程, 显示

** 当前屏渲染(On-Screen Rendering)
GPU的渲染操作是在当前用于显示的屏幕缓冲区中进行的

** 离屏渲染(Off-Screen Rendering)
GPU在当前屏幕缓冲区以外, 新开辟一个缓冲区进行渲染操作
圆角属性(与 maskToBounce一起使用), 图层蒙版,阴影遮罩, 光栅化! 当有些控件设置某些属性, 标记为在为合成之前, 不能直接在当前屏幕显示时, 就会触发

  • 为何要避免离屏渲染?
  • 创建新的渲染缓冲区, 上下文切换
  • CPU 和 GPU在图像显示上做了大量工作, 离屏渲染是触发了 GPU 多通道渲染管线, 产生了额外的开销!
    *-> 增加 GPU 工作量, 可能导致CPU+GPU>16.7s, 导致掉帧或者卡顿.

UIView 和 CALayer 设计原则-->单一职责
*/

pragma mark - OC 原理面试题

/** 1. OC 分类原理 category

  • 你用分类都做了那些事 ?
    ** 声明私有方法
    ** 分解体积庞大的类文件
    ** 把 framework 的私有方法公开化

  • 特点
    ** 运行时决议(通过 runtime给宿主类添加方法)
    ** 可以为系统类添加分类(UIVIew 添加获取坐标)

  • 分类中可以添加哪些内容?
    ** 实例方法
    ** 类方法
    ** 协议
    ** 属性(只是添加了set get 方法, 并不是添加了实例变量, 通过关联对象可添加变量)

struct objc_category {
char * _Nonnull category_name
char * _Nonnull class_name
struct objc_method_list * _Nullable instance_methods
struct objc_method_list * _Nullable class_methods
struct objc_protocol_list * _Nullable protocols
}

分类加载调用栈
_objc_init
map_2_images
map_images_nolock
_read_images
remethodizeClass ***

-> 多个分类重写同一个方法, 最后编译分类中的方法, 会生效!

method.attachLists(mlist, mcount)
memmove() 将分类的方法, 插入到宿主类方法列表前面

*** 能否给分类添加成员变量?
** 不能, 但是可以通过关联对象方法, 达到添加成员变量的效果

objc_getAssociatedObject(<#id _Nonnull object#>, <#const void * _Nonnull key#>)

*** 关联对象本质

  • 关联对象共有AssociationsManager 管理并在 AssociationHashMap 存储
  • 所有对象的关联内容都在同一个全局容器中
  • 根据 对象的地址作为 key, value+policy 封装成AssociationMap作为值, 添加到 AssociationHashMap 中统一管理.
    ---> value 设置为 nil, 可以清除关联对象的值
    // objc_getAssociatedObject(<#id _Nonnull object#>, <#const void * _Nonnull key#>)
    // objc_setAssociatedObject(<#id _Nonnull object#>, <#const void * _Nonnull key#>, <#id _Nullable value#>, <#objc_AssociationPolicy policy#>)
    // objc_removeAssociatedObjects(<#id _Nonnull object#>)
    */

/** 2. 类的扩展(Extention)

** a.一半用扩展做什么

  • 声明私有属性
  • 声明私有方法
  • 声明私有成员变量

** b.分类和扩展的区别

  • 编译是决定
  • 只以声明的形式存在, 多数情况寄生在宿主类的 .m中
  • 不能为系统类添加扩展

*/

/** 3. 代理(delegate)
** 设计模式

  • @ protocol 方式实现
  • 一对一
    */

/** 4.通知(NSNoticefication)
** 基于观察者模式实现的, 跨层消息传递机制.

  • 传递方式: 一对多

*** 如何实现通知机制?

  • Noticefication_map(name, observer_list(observer1, observer2...))

*/

/** 5. KVO 机制
** 观察者设计模式
** apple采用 isa 混写(isa_swizzing)来实现 kvo

  • addObserverA -> NSKVONotifying_A(运行时动态创建子类) -> 重写了 setter

    • (void)didChangeValueForKey:(NSString *)key
    • (void)willChangeValueForKey:(NSString *)key
      ???
      ** a.通过 KVC 设置 value 能否生效
  • setMValue:(id)value forKey:
  • YES
  • 调用了 set 方法

** b.通过成员变量直接赋值value, 能否生效

  • NO
  • 可以手动添加 willChangeValueForKey,didChangeValueForKey 就可以生效 (手动 KVO)
    */

// KVO运行时动态生成的子类, 重写了 set 方法, 达到监听效果

  • (void)setMValue:(id)value forKey:(NSString *)key{
    [self willChangeValueForKey:key];
    [super setValue:value forKey:key];
    [self didChangeValueForKey:key];
    }

/** 6. KVC 底层实现
** 键值编码技术

  • 相关方法 valueForKey setValueForKey
  • valueForKey
    Accessor Method is Exit? -> YES (Invoke end)
    -> NO
    Instance var is exit? (+ (BOOL)accessInstanceVariablesDirectly{})
    ->YES (Invoke end)
    -> NO -> valueForUndefinedKey ,抛出异常 exception
  • Accessor Method
  • 成员变量判断 Instance var <_key> <_iskey>

** setValueForKey

  •  Setter Method is exit ? -> YES (Invoke end)
         ->NO
             Instance var is exit ?(+ (BOOL)accessInstanceVariablesDirectly{})
                 -> YES (Invoke end)
                 -> NO -> setValueForUndefinedKey: 抛出异常 exception
    

*/

/** 7. 属性关键字
** 读写权限
readOnly readWrite
** 原子性
nonatomic atomic(读, 写 保证线程安全->对一个数组进行插入删除元素, 不能保证线程安全)
** 引用技术
retain/stong
assign : a.能够修饰基本数据类型; b.修饰对象类型时,不改变其应用计数; 会产生悬垂指针
weak : a.不改变修饰对象的引用计数; b.所指向对象在被释放之后会自动设置为 nil
copy : a.;;

  • 浅拷贝 : 增加对象的引用计数, 不会增加内存空间 未开辟内存空间 增加引用计数
  • 深拷贝 : 让目标对象指针和源对象指针, 指向两片相同的内存 开辟内存空间 不会增加引用计数

mutableOBJ copy 不可变 深拷贝
mutableOBJ mutableCopy 可变 深拷贝
immutableOBJ copy 不可变 浅拷贝
immutableOBJ mutableCopy 可变 深拷贝

可变对象的 copy, 都是深 copy
不可变对象的copy, 是浅 copy
@property(copy) NSMutableArray *array;
copy 出来的是 NSArray, 不可变(addObj 报错)
*/

/** 8. MRC 如何重写 retain 修饰变量的 setter
*/

//- (void)setObj:(id)obj {
// if(_obj != obj) {
// [_obj release];
// _obj = [obj retain];
// }
//}

pragma mark - 内存管理

/** 01. 内存

  • stack: 方法调用
  • heap : allo 创建的对象
  • .bss : 未初始化的全局变量
  • .data: 已初始化的全局变量
  • .text: 程序代码

*** 内存管理方案

  • TaggedPointer (NSNumber)
  • NONPOINTER_ISA (非指针类 isa)
  • 散列表(引用计数表, 弱引用)

*** NONPOINTER_ISA arm64

  • 64bit
  • 0-15 : indexed =1, 存储了内存管理相关数据

*** 散列表(side Tables 结构)

  • spinlock_t(自旋锁)
  • RefcountMap(引用计数表)
  • weak_table_t(弱引用表)
    ??? 为什么不是一个 sidetable
    分离锁:
    用一个表, 不同线程操作的时候存在效率问题.
    用多个表, 可以并发处理不同对象引用计数.

??? 怎样实现快速分流
sideTable本质是一张 Hash 表
key(对象指针) ->(hash 函数)-> Value(sideTable)
查找元素, 不需要遍历, 根据 hash函数取对应index!

*** spinlock_t(自旋锁)

  • "忙等"(当前线程不断去获取锁的状态)
  • 适用于轻量级访问.

*/

/*** RefcountMap(引用计数表)

  • size_t unsigned long
  • 计算时需要 右移两位
    */

/*** weak_table_t(弱引用表)

  • 实现也是 hash 表
    */

pragma mark - 网络

/** 0. 请求报文
方法 url 协议版本 crlf
首部字段名: 值
实体主题

*** 响应报文
版本 状态码 短语 crlf
首部字段名: 值
实体主题

**** http 请求方式
GET POST HEAD PUT DELETE OPTIONS

??? GET/POST 区别
GET请求参数拼接到 URL 后面, POST 请求参数放在 Body 中
GET参数长度限制2048个字符, POST 一般没有限制
GET 请求不安全, POST 请求安全

-> 语义角度分析
GET: 用来获取资源, 安全, 幂等, 可缓存
POST: 处理资源, 不安全, 不幂等, 不可缓存

安全性: 不应该引起 sever 端任何状态变化 // GET HEAD OPTIONS
幂等性: 同一个请求方法执行多次和执行一次的效果完全相同 // PUT DELETE
可缓存: 请求是否可以被缓存 // GET HEAD

??? 创建的状态码, 含义
1...
2...正常
3...转发
4...请求错误
5...服务器错误

??? http 三次握手 四次挥手
// 三次握手, 建立连接

  1. syn 2.syn, ACK

  2. ACK

  3. http 请求报文 5. http 响应报文

// 四次挥手断开连接
6.FIN 7.ACK
8.FIN,ACK
9.ACK

??? http特点

  • 无连接, 通过 http 持久连接来解决无连接特点
  • 无状态, cookie/session

** 持久连接
头部字段
connection: keep-alive
time: 20 // 持续时间
max:10 // http请求最多发送次数

?? 怎样判断一个请求结束
content-length:1024 // 根据接受到数据长度
chunked: 最后有个空的 chunked

?? charles 抓包原理
中间人攻击

**** HTTPS
https = http + ssl

??? https 建立流程

Client -> TLS 版本号, 支持的加密算法, random C -> Server
<- 商定的加密算法, random S, server 证书 <-
验证证书
组装会话秘钥
-> 通过 sever 的公钥对预主秘钥进行加密传输 ->
通过私钥解密得到预主秘钥
组装会话秘钥
-> 发送加密的握手消息 ->
<- 发送加密的握手消息 <-

会话秘钥 = random S + random C + 预主秘钥 // 对称加密

?? https 使用了哪些加密手段
连接过程使用的非对称加密
后续传输使用对称加密

??? TCP / UDP
TCP:
特点: 面向连接, 可靠传输, 面向字节流, 流量控制, 拥塞控制
面向连接: 三次握手(防超时, 误建立连接), 四次挥手
可靠传输: 无差错, 不丢失, 不重复, 按序到达

 UDP:
     特点: 无连接, 尽最大努力交互(不可靠), 面向报文(既不合并, 也不拆分, 将应用层的报文直接传输到)
     功能: 复用, 分用

*** DNS 解析

??? DNS 劫持
钓鱼 DNS 返回错误的 IP
DNS 请求使用 UDP 数据包, 端口号53; 发生在 http 连接之前.

怎样解决 DNS 劫持?
使用 http 协议向 httpDNS 80 端口 服务器请求
使用长连接

**** cookie
cookie 主要用来记录用户状态, 区分用户, 状态保存在客户端;

?? 怎样修改 cookie
新的 cookie 覆盖旧的 cookie;
覆盖规则: name, path, domain 等需要跟原 cookie 一致;

?? 怎样删除 cookie
新的 cookie 覆盖旧的 cookie; 设置 expires= 过期的时间 或者 maxAge=0
?? 怎样保证 cookie 安全
对 cookie 进行加密;
只在 https 上携带 cookie;
设置httpOnly;

?? session
session存放在服务端

*/

/**

??? 什么是 ARC
ARC 是由 LLVM 和 runtime 共同协作的自动引用计数内存管理机制

??? weak 指针指向的对象, 释放后, 至 nil
对象被废弃之后, 会调用一个清除弱引用的方法, 方法会通过哈希函数查找对象在哈希表中的位置, 来提取弱引用指针的数组, 然后遍历置为nil

??? 苹果如果实现 autoreleasepool
autoreleasepool是以栈为节点, 通过双向链表实现的结构

??? 循环引用
runloo -> timer 中间对象(弱引用) 对象<- VC

??? 什么是 block
block 是将 函数 及其 执行上下文 封装器来的 对象

??? block 截获变量
局部变量
基本数据类型: 截获局部变量对应的值
对象类型: 连同所有权修饰符一起截获
静态局部变量: 以指针形式
全局变量, 静态全局变量: 不截获

对被截获变量进行 赋值 操作, 需要使用__block 修饰变量
对静态局部变量, 全局变量, 静态全局变量赋值, 不需要使用__block 修饰
*/

pragma mark - 算法

/** 0. 字符串反转算法
hash 算法
求无需数组中的中位数

*/

// 0. 字符串反转算法
void char_reverse(char* cha)
{
    // 指向第一个字符
    char* begin = cha;
    // 指向最后一个字符
    char* end = cha + strlen(cha) - 1;
    
    while (begin < end) {
        // 交换前后两个字符,同时移动指针
        char temp = *begin;
        *(begin++) = *end;
        *(end--) = temp;
    }
}

// 1. 链表反转
struct Node* reverseList(struct Node *head)
{
    // 定义遍历指针,初始化为头结点
    struct Node *p = head;
    // 反转后的链表头部
    struct Node *newH = NULL;
    
    // 遍历链表
    while (p != NULL) {
        
        // 记录下一个结点
        struct Node *temp = p->next;
        // 当前结点的next指向新链表头部
        p->next = newH;
        // 更改新链表头部为当前结点
        newH = p;
        // 移动p指针
        p = temp;
    }
    
    // 返回反转后的链表头结点
    return newH;
}

// 有序数组合并
void mergeList(int a[], int aLen, int b[], int bLen, int result[])
{
    int p = 0; // 遍历数组a的指针
    int q = 0; // 遍历数组b的指针
    int i = 0; // 记录当前存储位置
    
    // 任一数组没有到达边界则进行遍历
    while (p < aLen && q < bLen) {
        // 如果a数组对应位置的值小于b数组对应位置的值
        if (a[p] <= b[q]) {
            // 存储a数组的值
            result[i] = a[p];
            // 移动a数组的遍历指针
            p++;
        }
        else{
            // 存储b数组的值
            result[i] = b[q];
            // 移动b数组的遍历指针
            q++;
        }
        // 指向合并结果的下一个存储位置
        i++;
    }
    
    // 如果a数组有剩余
    while (p < aLen) {
        // 将a数组剩余部分拼接到合并结果的后面
        result[i] = a[p++];
        i++;
    }
    
    // 如果b数组有剩余
    while (q < bLen) {
        // 将b数组剩余部分拼接到合并结果的后面
        result[i] = b[q++];
        i++;
    }
}

// hash 算法 - 在一个字符串中找到第一个只出现一次的字符
char findFirstChar(char* cha)
{
    char result = '\0';
    // 定义一个数组 用来存储各个字母出现次数
    int array[256];
    // 对数组进行初始化操作
    for (int i=0; i<256; i++) {
        array[i] =0;
    }
    // 定义一个指针 指向当前字符串头部
    char* p = cha;
    // 遍历每个字符
    while (*p != '\0') {
        // 在字母对应存储位置 进行出现次数+1操作
        array[*(p++)]++;
    }
    
    // 将P指针重新指向字符串头部
    p = cha;
    // 遍历每个字母的出现次数
    while (*p != '\0') {
        // 遇到第一个出现次数为1的字符,打印结果
        if (array[*p] == 1)
        {
            result = *p;
            break;
        }
        // 反之继续向后遍历
        p++;
    }
    
    return result;
}

// 查找两个自视图共同父视图算法
- (NSArray  *)findCommonSuperView:(UIView *)viewOne other:(UIView *)viewOther
{
    NSMutableArray *result = [NSMutableArray array];
    
    // 查找第一个视图的所有父视图
    NSArray *arrayOne = [self findSuperViews:viewOne];
    // 查找第二个视图的所有父视图
    NSArray *arrayOther = [self findSuperViews:viewOther];
    
    int i = 0;
    // 越界限制条件
    while (i < MIN((int)arrayOne.count, (int)arrayOther.count)) {
        // 倒序方式获取各个视图的父视图
        UIView *superOne = [arrayOne objectAtIndex:arrayOne.count - i - 1];
        UIView *superOther = [arrayOther objectAtIndex:arrayOther.count - i - 1];
        
        // 比较如果相等 则为共同父视图
        if (superOne == superOther) {
            [result addObject:superOne];
            i++;
        }
        // 如果不相等,则结束遍历
        else{
            break;
        }
    }
    
    return result;
}

- (NSArray  *)findSuperViews:(UIView *)view
{
    // 初始化为第一父视图
    UIView *temp = view.superview;
    // 保存结果的数组
    NSMutableArray *result = [NSMutableArray array];
    while (temp) {
        [result addObject:temp];
        // 顺着superview指针一直向上查找
        temp = temp.superview;
    }
    return result;
}


//求一个无序数组的中位数
int findMedian(int a[], int aLen)
{
    int low = 0;
    int high = aLen - 1;
    
    int mid = (aLen - 1) / 2;
    int div = PartSort(a, low, high);
    
    while (div != mid)
    {
        if (mid < div)
        {
            //左半区间找
            div = PartSort(a, low, div - 1);
        }
        else
        {
            //右半区间找
            div = PartSort(a, div + 1, high);
        }
    }
    //找到了
    return a[mid];
}

int PartSort(int a[], int start, int end)
{
    int low = start;
    int high = end;
    
    //选取关键字
    int key = a[end];
    
    while (low < high)
    {
        //左边找比key大的值
        while (low < high && a[low] <= key)
        {
            ++low;
        }
        
        //右边找比key小的值
        while (low < high && a[high] >= key)
        {
            --high;
        }
        
        if (low < high)
        {
            //找到之后交换左右的值
            int temp = a[low];
            a[low] = a[high];
            a[high] = temp;
        }
    }
    
    int temp = a[high];
    a[high] = a[end];
    a[end] = temp;
    
    return low;
}


你可能感兴趣的:(inverview)