源码都是基于objc-782,818版本,Swift5 ;老版本可能有不同的地方

[[NSObject alloc] init] 和 [NSObject new] 的区别

我采用3种方式来验证

id a = [ClassA alloc];

id aa = [[ClassA alloc] init];

id aaa = [ClassA new];

第一个,执行的堆栈,发现执行了2次 callAlloc,最终执行到_objc_rootAllocWithZone

id a = [ClassA alloc];
        
#0 _objc_rootAllocWithZone 
#1 callAlloc(objc_class*, bool, bool) 
#2 _objc_rootAlloc
#3 +[NSObject alloc]
#4 callAlloc(objc_class*, bool, bool)
#5 objc_alloc

第二个,执行堆栈,这里就有点奇怪了,感觉编译器做了优化,如果 alloc 后面紧跟 init,那么直接就执行objc_alloc_init

#0 _objc_rootAllocWithZone 
#1 callAlloc(objc_class*, bool, bool)
#2 objc_alloc_init

第三个,执行堆栈,除了入口函数不一样,其他一模一样。

#0 _objc_rootAllocWithZone 
#1 callAlloc(objc_class*, bool, bool)
#2 objc_opt_new

总结:

  • [alloc] init ] 和 new ,执行的结果是一样的 , 面试的时候可以理直气壮的说两者是“一模一样的”。
  • id a = [ClassA alloc]; [a init]; 和 id aa = [[ClassA alloc] init]; 结果是一样的,但是堆栈有较大不同

[[NSObject alloc] init] 中 init 是做初始化的工作么?

id
_objc_rootInit(id obj)
{
    // In practice, it will be hard to rely on this function.
    // Many classes do not properly chain -init calls.
    return obj;
}

总结:init 没有做任何事情

弱引用指针存储是用什么数据结构?

摘取了部分源码:

static weak_entry_t *
weak_entry_for_referent(weak_table_t *weak_table, objc_object *referent)
{
    ASSERT(referent);

    weak_entry_t *weak_entries = weak_table->weak_entries;

    if (!weak_entries) return nil;

    size_t begin = hash_pointer(referent) & weak_table->mask;
    size_t index = begin;
    size_t hash_displacement = 0;
    while (weak_table->weak_entries[index].referent != referent) {
        index = (index+1) & weak_table->mask;
        if (index == begin) bad_weak_table(weak_table->weak_entries);
        hash_displacement++;
        if (hash_displacement > weak_table->max_hash_displacement) {
            return nil;
        }
    }
    
    return &weak_table->weak_entries[index];
}

答案:存储的方式是数组,但是用了Hash算法-开放定位法,所以存储的是Hash表

分类重写主类的方法,会把函数替换掉么?

答:不会,函数替换只是表面现象;主要原因是函数寻找过程,优先寻找到分类的方法,主函数的方法其实还是存在的。

ClassA +load 中执行 [ClassB alloc],在ClassB +load 执行 [ClassA alloc] 会怎么样

// Call +load methods (without runtimeLock - re-entrant)
call_load_methods();

答:不会存在任何问题,1:load方法执行的时候,类的相关信息都已经准备完毕 2:执行load方法,没有添加 runtime lock,所以不会出现死锁现象

UIView设置Frame,是直接设置CALayer的Frame么,为什么CALayer有隐式动画而UIView没有

答:大部分设置UIView的属性,都会设置到CALayer上,而没有出现动画是因为CAAction,只有在UIView.animation block里面,uiview作为calayer的代理才会返回CAAction , 参考官方文档

NSNumber *number1 = @(1); 和 NSNumber *number2 = @(0xEFFFFFFFFFFFFFFF); 有什么区别

总结:TaggedPointer的区别,理论上TaggedPointer可以存储7个字节+ 4bit = 60bit的大小数据

ARC下 什么情况下会执行对象的autoRelease方法

//todo

Swift中函数调用用什么方式

答:静态派发和动态派发,动态派发又分 虚拟表派发 和 消息发送(@objc)

Swift中结构体或者基础数据中,函数是调用是什么方式

答:静态派发

Swift中扩展的函数,是什么调用方式

答:静态派发

Swift中结构体中使用Block,会出现循环引用的情况么?

//todo

Swift中数组范型可以用协议么?为什么

答:可以,如果数组范型是协议,那么数组存储的是一个特殊的数据结构,witnessTable,具体参考文档