iOS 美团面试整理

1, HTTP和HTTPS 区别,HTTPS证书验证原理

区别

1,HTTP 明文传输,数据都是未加密的,安全性较差,HTTPS(SSL+HTTP) 数据传输过程是加密的,安全性较好。
2,使用 HTTPS 协议需要到 CA(Certificate Authority,数字证书认证机构) 申请证书,一般免费证书较少,因而需要一定费用。证书颁发机构如:Symantec、Comodo、GoDaddy 和 GlobalSign 等。
3,HTTP 页面响应速度比 HTTPS 快,主要是因为 HTTP 使用 TCP 三次握手建立连接,客户端和服务器需要交换 3 个包,而 HTTPS除了 TCP 的三个包,还要加上 ssl 握手需要的 9 个包,所以一共是 12 个包。
4,HTTP 和 HTTPS 使用的是完全不同的连接方式,用的端口也不一样,前者是 80,后者是 443。
HTTPS 其实就是建构在 SSL/TLS 之上的 HTTP 协议,所以,要比较 HTTPS 比 HTTP 要更耗费服务器资源

HTTPS证书验证原理

1、客户端发起 HTTPS 请求
这个没什么好说的,就是用户在浏览器里输入一个 https 网址,然后连接到 server 的 443 端口。
2、服务端的配置
采用 HTTPS 协议的服务器必须要有一套数字证书,可以自己制作,也可以向组织申请,区别就是自己颁发的证书需要客户端验证通过,才可以继续访问,而使用受信任的公司申请的证书则不会弹出提示页面(startssl 就是个不错的选择,有 1 年的免费服务)。
这套证书其实就是一对公钥和私钥,如果对公钥和私钥不太理解,可以想象成一把钥匙和一个锁头,只是全世界只有你一个人有这把钥匙,你可以把锁头给别人,别人可以用这个锁把重要的东西锁起来,然后发给你,因为只有你一个人有这把钥匙,所以只有你才能看到被这把锁锁起来的东西。
3、传送证书
这个证书其实就是公钥,只是包含了很多信息,如证书的颁发机构,过期时间等等。
4、客户端解析证书
这部分工作是有客户端的TLS来完成的,首先会验证公钥是否有效,比如颁发机构,过期时间等等,如果发现异常,则会弹出一个警告框,提示证书存在问题。
如果证书没有问题,那么就生成一个随机值,然后用证书对该随机值进行加密,就好像上面说的,把随机值用锁头锁起来,这样除非有钥匙,不然看不到被锁住的内容。
5、传送加密信息
这部分传送的是用证书加密后的随机值,目的就是让服务端得到这个随机值,以后客户端和服务端的通信就可以通过这个随机值来进行加密解密了。
6、服务端解密信息
服务端用私钥解密后,得到了客户端传过来的随机值(私钥),然后把内容通过该值进行对称加密,所谓对称加密就是,将信息和私钥通过某种算法混合在一起,这样除非知道私钥,不然无法获取内容,而正好客户端和服务端都知道这个私钥,所以只要加密算法够彪悍,私钥够复杂,数据就够安全。
7、传输加密后的信息
这部分信息是服务段用私钥加密后的信息,可以在客户端被还原。
8、客户端解密信息
客户端用之前生成的私钥解密服务段传过来的信息,于是获取了解密后的内容,整个过程第三方即使监听到了数据,也束手无策。

参考文章HTTP和HTTPS 区别 ,HTTP/HTTPS

2,常用的加密方式

常用加密算法
编码方式 : Base64 Base58
哈希(散列)函数 : MD5(消息摘要算法) SHA1 SHA256 SHA512
对称加密算法 : DES AES
非对称加密算法 : RSA(公钥、私钥) ECC

参考文章常用加密算法

3,isKindOfClass、isMemberOfClass区别,底层代码实现差别

isKindOfClass 可判断是否处于继承链上的类

  + (BOOL)isKindOfClass:(Class)cls {
    for (Class tcls = object_getClass((id)self); tcls; tcls = tcls->superclass) {
        if (tcls == cls) return YES;
    }
    return NO;
}

isMemberOfClass 只能判断本身的类是否一致

   + (BOOL)isMemberOfClass:(Class)cls {
    return object_getClass((id)self) == cls;
}

区别是isKindOfClass 是for循环沿着继承链,一级一级向上查找,isMemberOfClass只是判断object_getClass((id)self),当前objc是一个类对象,那么获取的类就是当前类的元类,如果objc是一个实例对象,那么获取的就是当前的类。

4,category,extension区别,从底层分析category为什么不能添加实例变量

Category是运行时决定生效的,Extension是编译时就决定生效的
Category可以为系统类添加分类,Extension不能
Category是有声明和实现,Extension直接写在宿主.m文件,只有声明
Category只能扩充方法,不能扩充成员变量和属性
如果Category声明了声明了一个属性,那么Category只会生成这个属性的set,get方法的声明,也就不是会实现
Category底层结构体 category_t 只有方法缓存,方法列表,协议列表以及属性列表,并没有存放成员变量的ivar,所以不支持添加成员变量,分析可参考这个文章 深入理解Category

5,objc_class , isa_t结构

objc_class
/// OC 中对象的结构体
struct objc_class : objc_object {
    Class ISA;
    Class superclass;
    cache_t cache;             // formerly cache pointer and vtable
    // bits用于存储类名、类版本号、方法列表、协议列表等信息,替代了Objective-C1.0中methodLists、protocols等成员变量。
    class_data_bits_t bits;    // class_rw_t * plus custom rr/alloc flags
    // class_rw_t 表示 class 是readwrite的 class_ro_t 表示class是readonly的
    class_rw_t *data() { 
        return bits.data();
    }
    void setData(class_rw_t *newData) {
        bits.setData(newData);
    }
  // ....省略一些方法
}
// class_ro_t存放的是编译期间就确定的;而class_rw_t是在runtime时才确定。class_ro_t是 class_rw_t中的一个属性,所以可以说class_rw_t是class_ro_t的超集
struct class_rw_t {
    uint32_t flags;
    uint32_t version;
    // 只读class 结构体
    const class_ro_t *ro;
    //方法列表
    method_array_t methods;
    //属性列表
    property_array_t properties;
    //协议列表
    protocol_array_t protocols;
    Class firstSubclass;
    Class nextSiblingClass;
}
struct class_ro_t {
    uint32_t flags;
    uint32_t instanceStart;
    uint32_t instanceSize;
    uint32_t reserved;

    const uint8_t * ivarLayout;

    const char * name;
    method_list_t * baseMethodList;
    protocol_list_t * baseProtocols;
    const ivar_list_t * ivars;

    const uint8_t * weakIvarLayout;
    property_list_t *baseProperties;
};
isa_t
union isa_t 
{
    isa_t() { }
    isa_t(uintptr_t value) : bits(value) { } 
    Class cls;
    uintptr_t bits; 

#   define ISA_MASK        0x0000000ffffffff8ULL
#   define ISA_MAGIC_MASK  0x000003f000000001ULL
#   define ISA_MAGIC_VALUE 0x000001a000000001ULL
    struct {
        uintptr_t nonpointer        : 1; // 代表是否开启NONPOINTER isa指针优化,之前的版本又叫index的其实一个意思苹果后来给这类优化方案起了名字NONPOINTER
        uintptr_t has_assoc         : 1; // 对象是否含有关联引用
        uintptr_t has_cxx_dtor      : 1; // 对象是否含有 C++ 或者 Objc 的析构器
        uintptr_t shiftcls          : 33; // 类的指针arm64下3bits,x86_64下44bits
        uintptr_t magic             : 6; // 判断对象是否初始化完成 arm下0x16 ,x86_64下 0x3b
        uintptr_t weakly_referenced : 1; //是否为弱引用的对象
        uintptr_t deallocating      : 1; //对象是否正在执行析构函数(是否在释放内存)
        uintptr_t has_sidetable_rc  : 1; // 判断是否需要用sidetable去处理引用计数,(extra_rc的大小影响到这个变量)
        uintptr_t extra_rc          : 19; //  存储该对象的引用计数值减一后的结果
#       define RC_ONE   (1ULL<<45)
#       define RC_HALF  (1ULL<<18)
    }; 
}; 

参考文章 objc_classisa_t

6,runloop相关内容

7,自动释放池相关内容

8,dealloc释放过程

对象内存销毁时刻表
1,调用-release 对象的引用计数为0
  a,对象正在被销毁,生命周期结束
  b,不在有新的 __weak 弱引用,否则将指向nil
  调用[self dealloc]
2,子类调用 -dealloc
  a,继承链最底层的子类调用 -dealloc
  b,MRC下则会手动释放实例变量
  c,继承关系中没一层父类调用 -dealloc
3,NSObject 调用 -dealloc
  调用object_dispose()方法
4,调用object_dispose()
  为C++对象们(iVars)调用 destructors
  为ARC对象们(iVars)调用 -release
  解除所有runtime 方法关联的对象
  解除所有 __weak 引用
  调用 free()

48F6BDE411B4BE47B2244486A72648A0.jpg

参考文章Dealloc还需要注意什么

9,如何动态替换实例对象的某个方法

  1. 可参考KVO的实现(动态创建一个子类,利用isa指针交换,在子类重写该方法,进行消息转发)
  2. 使用class_replaceMethod/class_addMethod函数在运行时对函数进行动态替换或增加新函数
  3. 直接用_objc_msgForward 走消息转发流程,然后在快转过程中进行替换

参考文章如何为一个实例动态替换方法

10,重排链表

题目描述

解题思路
1、通过双指针,找到链表中间节点,然后将之前链表分为前后两个链表(通过慢指针断开))
2、反转后链表
3、将前后两个链表进行合并,先前链表内容,然后再是后链表内容
4、如果还有两边不为空,则直接添加单最终链表的尾部

代码实现
 /**
 * Definition for singly-linked list.
 * public class ListNode {
 *     public var val: Int
 *     public var next: ListNode?
 *     public init() { self.val = 0; self.next = nil; }
 *     public init(_ val: Int) { self.val = val; self.next = nil; }
 *     public init(_ val: Int, _ next: ListNode?) { self.val = val; self.next = next; }
 * }
 */
class Solution {
    func reorderList(_ head: ListNode?) {
        if head == nil || head?.next == nil {
            return
        }
        let node: ListNode? = head
        var slow: ListNode? = head
        var fast: ListNode? = head?.next
        while fast != nil && fast?.next != nil {
            slow = slow?.next
            fast = fast?.next?.next
        }
        let halfNode: ListNode? = slow?.next
        slow?.next = nil
        let reverseNode: ListNode? = self.reverseReorderList(halfNode)
        self.mergeNodeList(node, reverseNode)
    }
    
    //反转链表
    func reverseReorderList(_ head: ListNode?) -> ListNode?{
        if head == nil {
            return nil
        }
        let curNode: ListNode? = head
        var nextNode: ListNode? = head
        var frontNode: ListNode? = head
        while curNode?.next != nil {
            nextNode = curNode?.next
            curNode?.next = nextNode?.next
            nextNode?.next = frontNode
            frontNode = nextNode
        }
        return frontNode
    }
    
    func mergeNodeList(_ n1: ListNode?, _ n2: ListNode?){
        var beforeNode: ListNode? = n1 //i
        var afterNode: ListNode? = n2   //j
        var resultNode: ListNode? = ListNode.init(0);
        while beforeNode != nil && afterNode != nil{
            resultNode?.next = beforeNode
            resultNode = resultNode?.next
            beforeNode = beforeNode?.next
            
            resultNode?.next = afterNode
            resultNode = resultNode?.next
            afterNode = afterNode?.next
        }
        resultNode?.next = beforeNode == nil ? afterNode : beforeNode
    }
}

11,有序数组中删除重复项

func removeDuplicates(_ nums: inout [Int]) -> [Int] {
        if nums.count == 0 {
            return 0
        }
        var left = 0
        var right = 1
        while right < nums.count {
            if nums[left] != nums[right] {
                left += 1
                nums[left] = nums[right]
            }
            right += 1
        }
        return nums
    }
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,386评论 6 479
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,939评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,851评论 0 341
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,953评论 1 278
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,971评论 5 369
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,784评论 1 283
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,126评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,765评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,148评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,744评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,858评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,479评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,080评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,053评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,278评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,245评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,590评论 2 343

推荐阅读更多精彩内容