iOS - 类

类的本质

每个对象都是其 类 的实例 , 被称为实例对象 . 每一个对象都有一个名为 isa 的指针,指向该对象的类。

typedef struct objc_object *id;
typedef struct objc_class *Class;

struct objc_class : objc_object {
    // Class ISA; 8 字节
    Class superclass;// 8 字节
    cache_t cache; // 16 字节            // formerly cache pointer and vtable
    class_data_bits_t bits;    // class_rw_t * plus custom rr/alloc flags
    /**/
}

struct objc_object {
private:
    isa_t isa;// 8 字节,对象实际分配的内存大小: 16
public:
    // ISA() assumes this is NOT a tagged pointer object
    Class ISA();

    // getIsa() allows this to be a tagged pointer object
    Class getIsa();
    /*...*/
}

对象是一个 id 类型 , 也就是一个指向 objc_object 结构体的指针。而我们看到 Class 是一个指向 objc_class 结构体指针,而 objc_class 继承于 objc_object , 因此,我们说 类也是一个对象 。 对象的本质实际上是个结构体指针

在 Objective-C 中,每个对象 ( 其根本是一个 objc_object 结构体指针 ) 都有一个名为 isa 的指针,指向该对象的类 ( 其根本是一个 objc_class 结构体 )

struct cache_t {
    struct bucket_t *_buckets;  // 8 字节
    mask_t _mask;       // 4 字节
    mask_t _occupied;   // 4 字节
}
struct bucket_t {
  private:
  #if __arm64__
    uintptr_t _imp;
    SEL _sel;
  #else
    SEL _sel;
    uintptr_t _imp;
  #endif
}
struct class_data_bits_t {
    uintptr_t bits;
    
    class_rw_t* data() {
        return (class_rw_t *)(bits & FAST_DATA_MASK);
    }
    /*.其他一些方法省略..*/
}

typedef unsigned long           uintptr_t;

// data pointer
#define FAST_DATA_MASK          0x00007ffffffffff8UL
mask_t cache_t::capacity() 
{
    return mask() ? mask()+1 : 0; 
}
mask_t cache_t::mask() 
{
    return _mask; 
}

 当没有调用过方法 , _mask 为 0 , 容量 capacity 也为 0 , 当 _mask 有值时 , 实际容量为 _mask + 1 .

 使用 occupied 来记录当前已经使用容量 .

 当使用容量到达总容量的 3/4 时 , 哈希桶会进行扩容 , 扩容容量为当前容量的两倍 ( 当使用超过 4 字节不扩容 ) . 扩容时会清空历史缓存 , 只保留最新 sel 和 imp .

struct class_rw_t {
    uint32_t flags;
    uint32_t version;
    const class_ro_t *ro;

    method_array_t methods;
    property_array_t properties;
    protocol_array_t protocols;

    Class firstSubclass;
    Class nextSiblingClass;
    char *demangledName;

#if SUPPORT_INDEXED_ISA
    uint32_t index;
#endif
    /*...*/
}

 当对象中包含属性, 会按属性占用内存开辟空间. 在结构体内存分配原则下自动偏移和补齐 .对象最终满足 16 字节对齐标准 .属性最终满足 8 字节对齐标准 .

struct class_ro_t {
    uint32_t flags;
    uint32_t instanceStart;
    uint32_t instanceSize;
#ifdef __LP64__
    uint32_t reserved;
#endif

    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;
}

 其实如名称一样 , class_rw_t即 read write , class_ro_t 即 read only . OC 为了动态的特性 , 在编译器确定并保存了一份 类的结构数据在 class_ro_t中 , 另外存储一份在运行时加载到 class_rw_t 中 , 供 runtime 动态修改使用 .

ro 是不可变的 , 而  rw 中  methods ,  properties 以及  protocols 内存空间是可变的 . 这也是  已有类 为什么可以动态添加方法 , 确不能动态添加属性的原因  ( 添加属性会同样添加成员变量 , 也就是 ivar . 而 ivar 是存储在 ro 中的 ) .
 
block:
block就是一个对象,本质为一个结构体

1、没有访问局部变量的block,并且没有强指针指向block,则此block为NSGlobalBlock

2、访问了局部变量的block,但是没有强指针指向block,则此block为NSStackBlock

3、访问了局部变量的block,并且有强指针指向block,则此block为NSMallocBlock

4、NSStackBlock类型的block,执行了copy操作之后,生成的block为NSMallocBlock

5、对NSGlobalBlock的block进行copy操作,什么也不会发生,生成的还是NSGlobalBlock类型的block
6、对NSStackBlock类型的block进行操作,会将block从栈上复制一份到堆中,生成NSMallocBlock类型的block

7、对NSMallocBlock类型的block进行copy操作,此block的引用计数会加1

8、block作为返回值时,会自动进行copy
int a = 10;
static int b = 20;
NSObject *obj1 = [[NSObject alloc] init];
NSObject *obj2 = [[NSObject alloc] init];
__weak typeof(obj2) weakObj = obj2;
__block NSObject *obj3 = [
[NSObject alloc] init];
__block int c = 10;
void(*test)(void) = (&__main_block_impl_0(
                                    __main_block_func_0,
                                    &__main_block_desc_0_DATA,
                                    a,
                                    &b,
                      obj1,
                      weakObj,
                      
obj3,
                      &c));
test
->FuncPtr(test);
struct __main_block_impl_0 {
  //存放了block的一些基本信息,包括isa,函数地址等等
  struct __block_impl impl;
  //存放block的一些描述信息
  struct __main_block_desc_0* Desc;
int a;
  int *b;
  NSObject *_strong obj1;
NSObject *_weak weakObj;
__Block_byref_obj3_0 *obj3;
__Block_byref_c_1 *c;   
//构造函数   __main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, int _a, int *_b,NSObject *__strong _obj,NSObject *__weak _weakObj, int flags=0) : a(_a), b(_b), obj1(_obj1), weakObj(_weakObj), obj3 {     impl.isa = &_NSConcreteStackBlock;     impl.Flags = flags;     impl.FuncPtr = fp;     Desc = desc;   } }; struct __block_impl {   void *isa; //isa指针,可以看出Block其实就是一个OC对象   int Flags; //标识,默认为0   int Reserved; //保留字段   void *FuncPtr;//函数内存地址 };

  __Block_byref_obj3_0 obj3 = {
    0,
    &obj3,//__forwarding指针指向自己
    33554432,
    sizeof(__Block_byref_obj3_0),
    __Block_byref_id_object_copy_131,//copy函数,根据obj3指针的引用类型决定是否对obj3对象进行retain操作
    __Block_byref_id_object_dispose_131,//dispose函数,在结构体从内存中移除的时候,会调用dispose函数,对obj3对象进行一次release操作
    objc_msgSend(objc_msgSend(objc_getClass( "NSObject"), sel_registerName("alloc")), sel_registerName("init"))
  };
  __Block_byref_c_1 c = {
    0,
    (__Block_byref_c_1 *)&c,//__forwarding指针指向自己
    0,
    sizeof(__Block_byref_c_1),
    10
  };
static struct __main_block_desc_0 {
  size_t reserved;      //保留字段
  size_t Block_size;    //__main_block_impl_0结构体所占内存大小
    void (*copy)(struct __main_block_impl_0*, struct __main_block_impl_0*); //copy函数
    void (*dispose)(struct __main_block_impl_0*); //dispose函数
} __main_block_desc_0_DATA = { 0, sizeof(struct __main_block_impl_0), __main_block_copy_0, __main_block_dispose_0}; 

 //copy指针指向的函数
 static void __main_block_copy_0(struct __main_block_impl_0*dst, struct __main_block_impl_0*src) {
   _Block_object_assign((void*)&dst->obj, (void*)src->obj, 3/*BLOCK_FIELD_IS_OBJECT*/);
     
   _Block_object_assign(&dst->obj3,src->obj3, 8/*BLOCK_FIELD_IS_BYREF*/);
   _Block_object_assign(&dst->c, src->c, 8/*BLOCK_FIELD_IS_BYREF*/);
 }
 //dispose指针指向的函数
 static void __main_block_dispose_0(struct __main_block_impl_0*src) {
   _Block_object_dispose((void*)src->obj, 3/*BLOCK_FIELD_IS_OBJECT*/);
      _Block_object_dispose((void*)src->obj3, 8/*BLOCK_FIELD_IS_BYREF*/);
   _Block_object_dispose((void*)src->c, 8/*BLOCK_FIELD_IS_BYREF*/);
 }
static void __main_block_func_0(struct __main_block_impl_0 *__cself) {
    int a = __cself->a; // bound by copy
    int *b = __cself->b; // bound by copy
    NSLog((NSString *)&__NSConstantStringImpl__var_folders_f3_lg91hwts5rjdlzjph0sn82m80000gp_T_main_064 cd6_mi_0, a, (*b), c);
}

block将我们所要调用的代码封装成了函数__main_block_func_0,并且将函数__main_block_func_0的内存地址保存在到void *FuncPtr

__main_block_func_0函数中,访问局部变量a和静态变量b时都是通过传递过来的__main_block_impl_0结构体拿到对应的成员变量进行访问,但是全局变量c并没有存放在结构体中,而是直接进行访问。

当访问局部变量为非引用类型的时候,会将局部变量的值捕获到block中,存放在一个同名的成员变量中。

当访问局部变量为引用类型的时候,生成一个strong类型的指针指向外部对象。

当访问局部变量为引用类型且用__weak修饰的时候,生成一个weak类型的指针指向外部对象。

当访问静态变量时,会将静态变量的地址捕获到block中,存放在一个同名的成员变量中。

当访问全局变量时,因为全局变量是一直存在,不会销毁,所以在block中直接访问全局变量,不需要进行捕获


__main_block_copy_0函数内部会调用 _Block_object_assign函数,它的主要作用是根据外部引用的对象的修饰符来进行相应的操作,如果外部对象是使用__strong来修饰,那么 栈上的block被复制到堆上的时候 _Block_object_assign函数会对此对象进行一次类似retain的操作,使得外部对象的引用计数+1。
__main_block_dispose_0函数内部会调用 _Block_object_dispose函数,它的作用就是在block内部函数执行完成之后对block内部引用的外部对象进行一次release操作。
 
__block只能用来修饰auto类型变量,无法用来修饰全局变量、静态变量等等
 
当block被复制到堆上之后,block所引用的__block变量也会被复制到堆上,这样在栈上和堆上各存在一份__block变量,此时将栈上__block变量中的__forwarding指针指向堆上__block变量的地址,同时,堆上的__block变量中的__forwarding指针指向它本身,那么此时,不管我们是访问栈上__block变量中的属性值还是堆上__block变量中的属性值,都是通过__forwarding指针访问到堆上的__block变量。
 

NSNotification:

存储

- (void) addObserver: (id)observer 
      selector: (SEL)selector 
        name: (NSString*)name 
       object: (id)object;
 
Obs为一个链表结构
1、如果注册通知时传入 name,那么会是一个双层的存储结构
named: {
  name: {
  object: struct Obs {observer, selector}
  }
}

找到NCTable中的named表,这个表存储了还有name的通知

name作为key,找到value,这个value依然是一个map

map的结构是以object作为key,obs对象为value,这个obs对象的结构上面已经解释,主要存储了observer & SEL

2、如果name为nil,object不为nil

nameless:{

  object: struct Obs {observer, selector}

}

3、如果name和object都为nil
Observation  *wildcard  链表中存储Obs {observer, selector}
 
- (id) addObserverForName: (NSString *)name 
          object: (id)object 
          queue: (NSOperationQueue *)queue 
        usingBlock: (GSNotificationBlock)block;
 
创建一个GSNotificationObserver类型的对象observer,并把queueblock保存下来
调用
- ( void) addObserver: (id)observer 
      selector: (SEL)selector 
        name: (NSString*)name 
       object: (id)object;
进行通知的注册
接收到通知时会响应observerdidReceiveNotification:方法,然后在didReceiveNotification:中把block抛给指定的queue去执行
 
调用通知:
- (void) postNotificationName: (NSString*)name object: (id)object userInfo: (NSDictionary*)info
 
通过name & object 查找到所有的obs对象(保存了observersel),放到数组中
通过performSelector:逐一调用sel,这是个同步操作
 
删除通知:
- (void) removeObserver: (id)observer 
           name: (NSString*)name 
          object: (id)object;
查找时仍然以nameobject为维度的,再加上observer做区分
因为查找时做了这个链表的遍历,所以删除时会把重复的通知全都删除掉
 
  异步通知:
- (void) enqueueNotification: (NSNotification*)notification
        postingStyle: (NSPostingStyle)postingStyle
        coalesceMask: (NSUInteger)coalesceMask
          forModes: (NSArray*)modes {
  // 判断是否需要合并通知
  if (coalesceMask != NSNotificationNoCoalescing) {
      [self dequeueNotificationsMatching: notification
                coalesceMask: coalesceMask];
  }
  switch (postingStyle) {
      case NSPostNow: 
          ...
          // 如果是立马发送,则调用NSNotificationCenter进行发送
 [_center postNotification: notification]; break; case NSPostASAP: // 添加到_asapQueue队列,等待发送,队列是双向链表实现  add_to_queue(_asapQueue, notification, modes, _zone); break; case NSPostWhenIdle: // 添加到_idleQueue队列,等待发送,队列是双向链表实现  add_to_queue(_idleQueue, notification, modes, _zone); break; } }

异步通知发送:

runloop触发某个时机,调用GSPrivateNotifyASAP()GSPrivateNotifyIdle()方法,这两个方法最终都调用了notify()方法

notify()所做的事情就是调用NSNotificationCenterpostNotification:进行发送通知

依赖runloop,所以如果在其他子线程使用NSNotificationQueue,需要开启runloop

所谓异步,指的是非实时发送而是在合适的时机发送,并没有开启异步线程

方法查找流程

当调用实例对象方法时 , 查找的将是类对象 .

当调用类方法是 , 查找的将是元类对象 .

1、查找本类缓存 , 找到直接跳转到 done;

2、查找本类方法列表 class_data_bits_t 中 , 找到后进行缓存并打印 , 直接跳转到 done;

3、循环遍历父类 , 查找方法缓存 , 找到直接跳转到 done;

4、查找方法列表 , 找到把方法添加到缓存并打印 , 直接跳转到 done;

5、直到遍历结束 superclass 为 nil;

6、判断是否实现 SEL_resolveInstanceMethod 方法,即 +(BOOL)resolveInstanceMethod:(SEL)sel;

7、如果SEL_resolveInstanceMethod方法返回yes向本类发送 SEL_resolveInstanceMethod 消息 , 即调用这个方法;

8、该方法执行完 ,进行 retry,即重新走一遍方法的查找流程;

9、如果SEL_resolveInstanceMethod没有找到方法的实现,进入转发流程;

10、SEL_forwardingTargetForSelector指定一个实现了该方法的对象(不能是self,否则进入死循环);

11、如果指定了target,则进入指定对象的方法查找流程;

12、如果没有指定targe,进入SEL_methodSignatureForSelector,生成一个NSMethodSignature 方法签名并返回;

13、接着对新生成的方法签名进行SEL_forwardInvocation,指派对象来接收这个消息;

Javascript Core:

JSVirtualMachine

一个JSVirtualMachine的实例就是一个完整独立的JavaScript的执行环境,为JavaScript的执行提供底层资源。

这个类主要用来做两件事情:

  1. 实现并发的JavaScript执行
  2. JavaScript和Objective-C桥接对象的内存管理
/* 对桥接对象进行内存管理 */
- (void)addManagedReference:(id)object withOwner:(id)owner;

/* 取消对桥接对象的内存管理 */
- (void)removeManagedReference:(id)object withOwner:(id)owner;

每一个JavaScript上下文(JSContext对象)都归属于一个虚拟机(JSVirtualMachine)。每个虚拟机可以包含多个不同的上下文,并允许在这些不同的上下文之间传值(JSValue对象)。

然而,每个虚拟机都是完整且独立的,有其独立的堆空间和垃圾回收器(garbage collector ),GC无法处理别的虚拟机堆中的对象,因此你不能把一个虚拟机中创建的值传给另一个虚拟机。

JavaScriptCore API都是线程安全的。你可以在任意线程创建JSValue或者执行JS代码,然而,所有其他想要使用该虚拟机的线程都要等待。

JSContext

一个JSContext对象代表一个JavaScript执行环境。在native代码中,使用JSContext去执行JS代码,访问JS中定义或者计算的值,并使JavaScript可以访问native的对象、方法、函数。

  • 如果想并发执行JS,需要使用多个不同的虚拟机来实现。
  • 可以在子线程中执行JS代码。

JSContext执行JS代码

  • 调用evaluateScript函数可以执行一段top-level 的JS代码,并可向global对象添加函数和对象定义
  • 其返回值是JavaScript代码中最后一个生成的值

JSValue

一个JSValue实例就是一个JavaScript值的引用。使用JSValue类在JavaScript和native代码之间转换数据

每个JSValue实例都来源于一个代表JavaScript执行环境的JSContext对象,这个执行环境就包含了这个JSValue对应的值。每个JSValue对象都持有其JSContext对象的强引用,只要有任何一个与特定JSContext关联的JSValue被持有(retain),这个JSContext就会一直存活。通过调用JSValue的实例方法返回的其他的JSValue对象都属于与最始的JSValue相同的JSContext。

猜你喜欢

转载自www.cnblogs.com/diyigechengxu/p/12484030.html