一套iOS底层试卷-答案

题目出处:
作者:Cooci
链接:https://juejin.cn/post/6983175020340051976
来源:稀土掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

正文

一、选择题(每题5分) ⚠️ 有单选有多选哦⚠️

在LP64下,一个指针的有多少个字节 分值5分

A: 4

B: 8

C: 16

D: 64


B

一个实例对象的内存结构存在哪些元素 分值5分

A:成员变量

B: supClass

C: cache_t

D: bit


A .实例对象的内存结构: isa + 成员变量.

其他的bcd.是类对象里面的数据

下面sizeof(struct3) 大小等于 分值5分

struct LGStruct1 {
    char b;                 1
    int c;                  4
    double a;               8
    short d;                2
}struct1;                   //15  .内存对齐 16

struct LGStruct2 {
    double a;               8
    int b;                  4
    char c;                 1
    short d;                2
}struct2;                   //15   .内存对齐 16


struct LGStruct3 {
    double a;               8
    int b;                  4
    char c;                 1
    struct LGStruct1 str1;  16
    short d;                2
    int e;                  4
    struct LGStruct2 str2;  16
}struct3;                   //51    内存对齐.内部最大的倍数.16的倍数    

复制代码

A: 48

B: 56

C: 64

D: 72


C 内存对齐.内部最大的倍数.16的倍数

下列代码: re1 re2 re3 re4 re5 re6 re7 re8输出结果 分值5分

BOOL re1 = [(id)[NSObject class] isKindOfClass:[NSObject class]]; 
BOOL re2 = [(id)[NSObject class] isMemberOfClass:[NSObject class]];   
BOOL re3 = [(id)[LGPerson class] isKindOfClass:[LGPerson class]];  
BOOL re4 = [(id)[LGPerson class] isMemberOfClass:[LGPerson class]];  
NSLog(@" re1 :%hhd\n re2 :%hhd\n re3 :%hhd\n re4 :%hhd\n",re1,re2,re3,re4);

BOOL re5 = [(id)[NSObject alloc] isKindOfClass:[NSObject class]];    
BOOL re6 = [(id)[NSObject alloc] isMemberOfClass:[NSObject class]];    
BOOL re7 = [(id)[LGPerson alloc] isKindOfClass:[LGPerson class]];     
BOOL re8 = [(id)[LGPerson alloc] isMemberOfClass:[LGPerson class]];   
NSLog(@" re5 :%hhd\n re6 :%hhd\n re7 :%hhd\n re8 :%hhd\n",re5,re6,re7,re8);

复制代码

A: 1011 1111

B: 1100 1011

C: 1000 1111

D: 1101 1111


C
1 , 类方法. 会去元类进行比较.是否是/是否是子类
0 , 类方法. 会去元类进行比较.是否是当前类
0 ,

(x + 7) & ~7 这个算法是几字节对齐 分值5分

A: 7

B: 8

C: 14

D: 16


B 也可以写成 (x + 7) >> 3 << 3
0111
1000

判断下列数据结构大小 分值5分

union kc_t {
    uintptr_t bits;
    struct {
        int a;              4
        char b;             1
    };
}

复制代码

A: 8

B: 12

C: 13

D: 16


A union 是联合体.共同体.公用一个内存.

元类的 isa 指向谁, 根元类的父类是谁 分值5分

A: 自己 , 根元类

B: 自己 , NSObject

C: 根元类 , 根元类

D: 根元类 , NSObject


BD 。

  • 根元类的isa指向自己,
  • 非根元类的isa 指向 根元类 .
  • 根元类的父类指向NSObject.

查找方法缓存的时候发现是乱序的, 为什么? 哈希冲突怎么解决的 分值5分

A: 哈希函数原因 , 不解决

B: 哈希函数原因 , 再哈希

C: 他存他的我也布吉岛 , 再哈希

D: 他乱由他乱,清风过山岗 , 不解决


B

objc_class 类对象

struct objc_class : objc_object {
  objc_class(const objc_class&) = delete;
  objc_class(objc_class&&) = delete;
  void operator=(const objc_class&) = delete;
  void operator=(objc_class&&) = delete;
    // Class ISA;
    Class superclass;
    cache_t cache;             // formerly cache pointer and vtable
    class_data_bits_t bits;    // class_rw_t * plus custom rr/alloc flags
    ....

cache_t 方法缓存表 . hash冲突的时候是发生在插入的方法里面的.主要关注插入的方法

struct cache_t {
...
public:
    void insert(SEL sel, IMP imp, id receiver);
    void copyCacheNolock(objc_imp_cache_entry *buffer, int len);
    void destroy();
    void eraseNolock(const char *func);
void cache_t::insert(SEL sel, IMP imp, id receiver)
{
...
    bucket_t *b = buckets();
    mask_t m = capacity - 1;  // 容量
    mask_t begin = cache_hash(sel, m); //方法名 和当前容量
    mask_t i = begin;

    // Scan for the first unused slot and insert there.
    // There is guaranteed to be an empty slot.
    do {
        if (fastpath(b[i].sel() == 0)) {
            incrementOccupied();
            b[i].set<Atomic, Encoded>(b, sel, imp, cls());
            return;
        }
        if (b[i].sel() == sel) {
            // The entry was added to the cache by some other thread
            // before we grabbed the cacheUpdateLock.
            return;
        }
    } while (fastpath((i = cache_next(i, m)) != begin));

    bad_cache(receiver, (SEL)sel);
#endif // !DEBUG_TASK_THREADS
}

unsigned cache_t::capacity() const
{
    return mask() ? mask()+1 : 0; 
}
static inline mask_t cache_hash(SEL sel, mask_t mask) 
{
    uintptr_t value = (uintptr_t)sel;
#if CONFIG_USE_PREOPT_CACHES
    value ^= value >> 7;
#endif
    return (mask_t)(value & mask);
}


#if CACHE_END_MARKER
static inline mask_t cache_next(mask_t i, mask_t mask) {
    return (i+1) & mask;
}
#elif __arm64__
static inline mask_t cache_next(mask_t i, mask_t mask) {
    return i ? i-1 : mask;
}
#else
#error unexpected configuration
#endif

消息的流程是 分值5分

A: 先从缓存快速查找

B: 慢速递归查找methodlist (自己的和父类的,直到父类为nil)

C: 动态方法决议

D: 消息转发流程


ABCD

类方法动态方法决议为什么在后面还要实现 resolveInstanceMethod 分值5分

A: 类方法存在元类(以对象方法形式存在), 元类的父类最终是 NSObject 所以我们可以通过resolveInstanceMethod 防止 NSObject 中实现了对象方法!

B: 因为在oc的底层最终还是对象方法存在

C: 类方法存在元类以对象方法形式存在.

D: 咸吃萝卜,淡操心! 苹果瞎写的 不用管


A

二、判断题 (每题5分)

光凭我们的对象地址,无法确认对象是否存在关联对象 分值5分



错. 在64位的系统下.对象地址的其中一位是用来判断是否有关联对象.在dealloc 的时候.会通过这位是否包含关联对象.来进行关联对象的释放

int c[4] = {1,2,3,4}; int *d = c; c[2] = *(d+2) 分值5分



对吧.

@interface LGPerson : NSObject{ UIButton *btn } 其中 btn 是实例变量 分值5分



NSObject 除外 元类的父类 = 父类的元类 分值5分



对象的地址就是内存元素的首地址 分值5分



类也是对象 分值5分



三、简单题 (每题 10分 合计 100分)

请把它当成一场面试,认真对待 希望大家耐心 切忌浮躁 (和谐学习 不急不躁)

17、怎么将上层OC代码还原成 C++代码 分值10分

xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc main.m -o main.cpp

18、怎么打开汇编查看流程,有什么好处 ? 分值10分

19、x/4gx 和 p/x 以及 p *$0 代表什么意思 分值10分

x/4gx 查看内存.分4块每块按8进制的显示

p/x 输出数据结构的首地址

p *0 打印0指针指向的内存

20、类方法存在哪里? 为什么要这么设计? 分值10分

类方法保存在元类里面,实例方法保存到类对象里面. 这么设计的好处.就是类方法只需要保存一份.不需要保存多分.

21、方法慢速查找过程中的二分查找流程,请用伪代码实现 分值10分

  1. 查找cache_t
  2. 查找当前类的方法列表
  3. 查找父类的方法列表
  4. 如果有.就将方法插入到cache_t
  5. 动态解析
  6. 消息转发
  7. 都没有找到.抛出异常

22、ISA_MASK = 0x00007ffffffffff8ULL 那么这个 ISA_MASK 的算法意义是什么? 分值10分

主要就是内存优化.通过对象指针进行isa_mask位运算.获取到对象的地址

23、类的结构里面为什么会有 rw 和 ro 以及 rwe ? 分值10分

类的结构主要是

  • isa.
  • superclass.
  • bits
    • rw (readwrite)
      • ro (readonly)
        • ivars
        • methods_list
        • protocol_list
        • property_list
        • ...
      • methods-array
      • protocol-array
      • property-array
      • ...
      • rwe (readwriteext,扩展)
        • class_ro_t_authed_ptr<const class_ro_t> ro;
        • method_array_t methods;
        • property_array_t properties;
        • protocol_array_t protocols;
        • char *demangledName;
        • uint32_t version;

24、cache 在什么时候开始扩容 , 为什么? 分值10分

    mask_t newOccupied = occupied() + 1;
    unsigned oldCapacity = capacity(), capacity = oldCapacity;
    if (slowpath(isConstantEmptyCache())) {
        // Cache is read-only. Replace it.
        if (!capacity) capacity = INIT_CACHE_SIZE;
        reallocate(oldCapacity, capacity, /* freeOld */false);
    }
    else if (fastpath(newOccupied + CACHE_END_MARKER <= cache_fill_ratio(capacity))) {
        // Cache is less than 3/4 or 7/8 full. Use it as-is.
    }
#if CACHE_ALLOW_FULL_UTILIZATION
    else if (capacity <= FULL_UTILIZATION_CACHE_SIZE && newOccupied + CACHE_END_MARKER <= capacity) {
        // Allow 100% cache utilization for small buckets. Use it as-is.
    }
#endif
    else {
        capacity = capacity ? capacity * 2 : INIT_CACHE_SIZE;
        if (capacity > MAX_CACHE_SIZE) {
            capacity = MAX_CACHE_SIZE;
        }
        reallocate(oldCapacity, capacity, true);
    }

25、objc_msgSend 为什么用汇编写 , objc_msgSend 是如何递归找到imp? 分值10分

不用汇编.还可以用啥😂.
参考方法查找的步骤

26、一个类的类方法没有实现为什么可以调用 NSObject 同名对象方法 分值10分

类方法保存在元类中.根元类的父类的superclass 指向的是nsobject
sel方法名传递的时候是没有传递+/- . 通过objc_msgSend 调用的方法接受者 和sel方法.

四、拓展满分题 (20分

提交一篇大师班学习期间,你写的最好的一篇博客 分值20分

五、总结

考试的题目偏向底层, 也比较贴合现在iOS的面试市场! 内容有深有浅,还可以继续挖坑 (👀)

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

推荐阅读更多精彩内容