1.weak 和 assign 不同

1.weak 和 assign 不同

  1. weak必须用于oc对象assign可以用于非oc对象
  2. weak可以用来解决循环引用问题weak修饰的属性表示一种非持有关系 给该对象设置新值时 设置方法既不保留新值也不释放旧值 在属性遭到摧毁时会自动制空
  3. weak可以用来修饰已经被强引用过得对象 比如使用xib进行布局时设置的属性

2.weak 的实现原理

  1. runtime维护了一个全局的weak引用表weak_table_t(封装版本为SideTable) 其底层是一个hash表(一种key value存储的数据结构 在cpp中体现为struct) 用于存储weak引用对象 key是所指对象地址 valueweak指针地址
  2. weak对象释放自动置空实现: 在对象释放的最后一步objc_clear_deallocating根据对象地址获取所有weak指针的数组 遍历这个数组把其中的额数据置为空 oc对象释放的顺序:
  3. objc_release,
  4. dealloc大部分对象是在这一环节被销毁的 其中主要做的事情为 object_dispose() associate 绑定的对象也是在这里销毁 所以不管是MRC还是ARC都不需要在dealloc中再次释放 associate 绑定对象,
  5. _objc_rootDealloc,
  6. objc_destructInstance,
  7. objc_clear_deallocating

3.copy修饰的属性

  1. copy即对象的浅拷贝 copy修饰的属性的值会有被保护的作用 一般copy会用来修饰不可变对象 比如 NSString, NSArray等 这样的对象在被可变对象接收以后 其值仍然不可变 可以利用此封装性质封装一些数据
  2. 自己的属性想实现copy需要实现NSCopying协议 并实现 - (id)copyWithZone:(NSZone *)zone方法

4.@property的本质

  1. 属性的本质是 getter + setter + ivar
  2. 属性自动合成(autosynthesis)的规则: 自动合成会生成下面五个东西
    // 该属性的偏移量 这个偏移量是硬编码 标示该变量距离存放对象的内存地址有多远
    OBJC_IVAR_$类名$属性名 
    gettersetter方法对应的实现函数
    // 成员列表
    ivar_list 
    // 方法列表
    method_list
    // 属性列表
    prop_list
    

    每增加一个属性 系统都会在 ivar_list 中添加一个成员变量的描述 在 method_list 中增加 gettersetter 方法的描述 在prop_list中给出属性描述 然后计算属性在对象中的偏移量然后根据偏移量的位置 实现具体的setter方法与getter方法

5. @synthesize 和 @dynamic

  1. @sythesize 如果没有手动实现gettersetter由编译器自动创建 默认为 @syntheszie var = _var;
  2. @dynamic gettersetter都需要手动创建

6.ARC下 不指定属性任何的关键字 默认的修饰符有哪些

  1. atomic readwrite string oc 对象
  2. atomic readwrite assign 基本类型

7.objc_msgSend()

Objective-C是动态语言 每个方法会在运行时被动态转为消息发送 即objc_msgSend(receiver, selector) oc类的基本结构:

struct objc_class {
  Class isa OBJC_ISA_AVAILABILITY; //isa指针指向Meta Class,因为Objc的类的本身也是一个Object,为了处理这个关系,runtime就创造了Meta Class,当给类发送[NSObject alloc]这样消息时,实际上是把这个消息发给了Class Object
  #if !__OBJC2__
  Class super_class OBJC2_UNAVAILABLE; // 父类
  const char *name OBJC2_UNAVAILABLE; // 类名
  long version OBJC2_UNAVAILABLE; // 类的版本信息,默认为0
  long info OBJC2_UNAVAILABLE; // 类信息,供运行期使用的一些位标识
  long instance_size OBJC2_UNAVAILABLE; // 该类的实例变量大小
  struct objc_ivar_list *ivars OBJC2_UNAVAILABLE; // 该类的成员变量链表
  struct objc_method_list **methodLists OBJC2_UNAVAILABLE; // 方法定义的链表
  struct objc_cache *cache OBJC2_UNAVAILABLE; // 方法缓存,对象接到一个消息会根据isa指针查找消息对象,这时会在method Lists中遍历,如果cache了,常用的方法调用时就能够提高调用的效率。
  struct objc_protocol_list *protocols OBJC2_UNAVAILABLE; // 协议链表
  #endif
  } OBJC2_UNAVAILABLE;

unrecognized selector 就是由于消息转发的时候没有在方法列表中找到产生的

消息转发过程 objc_msgForward:

  1. objc在向一个对象发送消息时runtime会根据对象的isa指针找到该对象所属的类 然后在该类的方法列表中查找目标方法 如果该类中没有这个方法 则去父类中查找 一直查找到父类的最上层
  2. 如果父类的最上层也没有找到相对应的方法 则会报unrecognized selector但在这之前 仍有三次补救的机会
  3. 第一次补救机会Method resolution: runtime会调用本类中+resolveInstanceMethod:+resolveClassMethod:让你提供一个函数实现 如果你添加了目标函数 那runtime会重新启动一次消息发送的过程 否则则运行到下一步 消息转发
  4. 第二次补救机会Fast forwarding: 如果目标对象实现了-forwardingTargetForSelector: runtime就会调用这个方法 根据这个方法返回的对象(不为nil或self)重启消息发送, 当然新的消息放松过程也会转移到返回的对象上面 否则则进行最后一次消息转发
  5. 第三次补救机会Normal forwarding: 首先runtime会发送-methodSignatureForSelector:获得函数的参数及返回类型 如果 -methodSignatureForSelector: 返回了nil 这时程序就会崩溃 如果返回了一个函数签名 则runtime会生成一个NSInvocation对象并发送-forwardInvocation:给目标对象 (有些框架 例如JSPatch 需要利用第三步返回的NSInvocation自定义实现 而直接调用了 objc_msgForward 这样原来的方法就不会被执行 而是走了别的实现)

8.下面的代码输出什么

  @implementation Son : Father
   - (id)init
   {
       self = [super init];
       if (self) {
           NSLog(@"%@", NSStringFromClass([self class])); // Son
           NSLog(@"%@", NSStringFromClass([super class])); // Son
       }
       return self;
   }
   @end

都是Son superself指向同一个消息接收者super会在父类中调用而已 但他仍然是本类对象

9.objc 中类方法和实例方法有什么本质区别和联系

类方法:

  1. 类方法是属于类对象的
  2. 类方法只能由类对象调用
  3. 类方法中的self是类对象
  4. 类方法可以调用其他类的方法
  5. 类方法中不能访问成员变量
  6. 类方法中不能直接调用对象方法

实例方法:

  1. 实例方法是属于实例对象的
  2. 实例方法由对象实例调用
  3. 实例方法中的self是实例对象
  4. 实例方法中可以访问成员变量
  5. 实例方法中可以调用实例方法
  6. 实例方法也可以调用类方法(通过类名)

10.能否想编译后的类中添加实例变量 运行时呢?

不能向编译后的类中添加实例变量 运行时可以 因为编译后的类已经在runtime中注册类结构体中的实例变量链表objc_Ivar_list和实例变量内存instance_size大小已确定

运行时可以添加但的在类被创建但还没有向runtime注册之前objc_allocateClassPair - objc_registerClassPair区间内

11.