iOS 的那些事儿iOS面试库面试那些事儿

iOS 头条面试

2019-08-03  本文已影响2人  uniapp

今天参加了头条的高级 iOS 岗位面试,1.5 h,一共两道题。一道问答,另外一道是算法。算法要求必须在纸上写出完整的代码,否则就算 Fail 。对于 iOS 开发者来说,除非处于研究目的,链表使用的场景真的不多。只能依据仅存在记忆中的大学 C 语言知识,边回忆变应用于眼前的算法题。最后结果完全在预料之中--「落榜」。

利用闲余时间,详细整理了一下问题和答案,供后来人准备。
问题1:iOS 消息调用过程;
问题2 :然后就拿出了一个链表的题目,要求手写算法:

两个链表 L1、 L2, 存储的是 10 以内的整数,求两个链表各个元素相加的结果。比如 L1 = 1 -> 2 -> 3 -> 5->9; L2 = 2 -> 1 -> 4 -> 7->1; 然后结果 res = 3->3->8->4->0.

答案 1 :iOS 消息调用属于基本知识,苹果官方有一个详细的介绍图:


image.png

iOS 工程中,调用对象的方法,就是向对象发送消息。我们知道,iOS 中的方法分为实例方法和对象方法。iOS 所有的对象都是继承至 NSObject, 编译完成后,在对象的定义中,存在一个实例方法链表、一个缓存方法链表。当对实例 son 发送消息后,会在 son 缓存方法链表中寻找;缓存中没有时,向实例方法链表寻找;再找不到,会向父类的实例方法缓存链表 -> 父类的实例方法链表寻找,直至 NSObject。在 NSObject 中会经历以下两个步骤:

1 - (BOOL)resolveInstanceMethod:(SEL)sel ; 
2 - (id)forwardingTargetForSelector:(SEL)aSelector ;

如果在步骤 2 中范围 nil, 就会触发 iOS 的崩溃。
当向 Son 发送类方法时,会首先向 Son 的元类 metaClass 中的类缓存方法链表中寻找,然后类方法链表,然后父类 metaClass 的缓存方法链表 -> 类方法链表,直至 NSObject . 在 NSObject 中会经历如下两个步骤:

实例的 methodList 链表中寻找方法,找不到时会寻找 Son 的类方法,仍然找不到时,会寻找父类的方法链表,直到 NSObject 。

其中不同对象间的切换,通过 isa 指针完成,实例 son 的 isa 指向类 Son, 类 Son 的 isa 指向元类,元类的 isa 指向父类的元类, 父类的元类向上传递,直至 NSObject .

NSObject 的指针 isa 指向其本身,在想 NSObject 发送消息时,会经历如下步骤:

1 + (BOOL)resolveClassMethod:(SEL)sel ; 
2 - (void)doesNotRecognizeSelector:(SEL)aSelector ;

当调用方法 2 时,会触发 iOS 的崩溃。利用以上机制,可以对resolveInstanceMethod 和 resolveClassMethod 两个方法进行方法交换,拦截可能出现的 iOS 崩溃,然后自定义处理。

如果理解了以上机制,就能明白这个题目

答案 2 首先讲解一下实现思路:计算链表和,需要从后往前计算,进位需要保存,用于下一个链表和。最后一个链表计算后,如果还存在进位,需要新建节点保存结果。

题目中链表属于单向,只能从前往后遍历,所以首先需要将链表反向,然后对结果采用头插法的方式进行保存。下面直接上代码:

- (void)jiSuanHe{
    ListNode *l1_1 = malloc(sizeof(ListNode));
    l1_1->value = 9;
    ListNode *l1_2 = malloc(sizeof(ListNode));
    l1_2->value = 8;
    l1_1->next = l1_2;
    ListNode *l1_3 = malloc(sizeof(ListNode));
    l1_3->value = 7;
    l1_2->next = l1_3;
    ListNode *l1_4 = malloc(sizeof(ListNode));
    l1_4->value = 5;
    l1_3->next = l1_4;
    ListNode *l1_5 = malloc(sizeof(ListNode));
    l1_5->value = 3;
    l1_5->next = NULL;
    l1_4->next = l1_5;
    
    ListNode *l2_1 = malloc(sizeof(ListNode));
    l2_1->value = 9;
    ListNode *l2_2 = malloc(sizeof(ListNode));
    l2_2->value = 8;
    l2_1->next = l1_2;
    ListNode *l2_3 = malloc(sizeof(ListNode));
    l2_3->value = 7;
    l2_2->next = l1_3;
    ListNode *l2_4 = malloc(sizeof(ListNode));
    l2_4->value = 5;
    l2_3->next = l1_4;
    //    ListNode *l2_5 = malloc(sizeof(ListNode));
    //    l2_5->value = 3;
    //    l2_5->next = NULL;
    //    l2_4->next = l1_5;
    
    ListNode *l1 = l1_1;
    ListNode *l2 = l2_1;
    
    printf("\n****\n");
    ListNode *l1_reverse = [self reverseList:l1];
    ListNode *l2_reverse = [self reverseList:l2];
    printf("\n--l1---\n");
    [self printList:l1_reverse];
    printf("\n--l2---\n");
    [self printList:l2_reverse];
    
    ListNode *temp1 = l1_reverse;
    ListNode *temp2 = l2_reverse;
    int jinWei = 0;
    int i = 0;
    ListNode *res;
    while (temp1 != NULL || temp2 != NULL) {
        int value1 = 0, value2 = 0;
        if (temp1 != NULL) {
            value1 = temp1 -> value;
        }
        if (temp2 != NULL) {
            value2 = temp2 -> value;
        }
        int yu = (value1 + value1 + jinWei) % 10;
        jinWei = (value1 + value1 + jinWei) / 10;
        ListNode *tempRes = malloc(sizeof(ListNode));
        tempRes -> value = yu;
        if (i == 0) {
            tempRes -> next = NULL;
        }else{
            tempRes -> next = res;
        }
        res = tempRes;
        temp1 = temp1 -> next;
        temp2 = temp2 -> next;
        i++;
    }
    
    if (jinWei != 0) {
        ListNode *tempRes = malloc(sizeof(ListNode));
        tempRes -> value = jinWei;
        tempRes -> next = res;
        res = tempRes;
    }
    
    printf("\n***结果\n");
    [self printList:res];
    printf("\n");
}

- (ListNode *)reverseList:(ListNode *)listNode{
    ListNode *resL;
    ListNode *l = listNode;
    int i = 0;
    while (l != NULL) {
        ListNode *temp = malloc(sizeof(ListNode));
        temp -> value = l -> value;
        if (i==0) {
            temp->next = NULL;
        }else{
            temp->next = resL;
        }
        resL = temp;
        i++;
        l = l -> next;
    }
    return resL;
}

- (void)printList:(ListNode *)listNode{
    ListNode *node = listNode;
    while (node != NULL) {
        printf("value = %d ", node->value);
        node = node->next;
    }
}

算法题目并不算难,但是想要在面试期间的短时间内顺利解决,则需要平常不断的积累。算法意识是一个程序员进阶必须经过的磨炼,从这个角度,进入头条的人都具备了成长的潜力。当然,作为雇主的头条大概率上也会越来越好。虽然这次失败了,但是对头条的印象却好起来了,希望以后还有尝试的机会,加油~

喜欢和关注都是对我的鼓励和支持~

上一篇下一篇

猜你喜欢

热点阅读