iOS底层原理相关问题

209 阅读5分钟

OC对象   

1.一个NSObject对象占用多少内存?

  •  系统分配了_16_个字节给NSObject对象(通过malloc_size函数获得)(以此为准,也就是说一个NSObject对象占用了16字节的内存,在64位环境(iOS)中malloc分配的字节数必定是16的倍数(内存对齐))

  •  但NSObject对象内部(Class isa)只使用了8个字节的空间(64bit环境下(iOS),可以通过class_getInstanceSize函数获得,getInstanceSize获得的字节数必定是8的倍数)

    // Person @interface Person : NSObject {
    int _age; } @property (nonatomic, assign) int height; @end @implementation Person @end

    // Student @interface Student : Person { int _no;
    BOOL isTrue; } @end @implementation Student @end

    int main(int argc, const char * argv[]) {
    @autoreleasepool {
    Person *person = [[Person alloc] init];
    NSLog(@"person - %zd", class_getInstanceSize([Person class])); //16
    NSLog(@"person - %zd", malloc_size((__bridge const void *)person)); //16

     Student *stu = [[Student alloc] init];        
     NSLog(@"stu - %zd", class_getInstanceSize([Student class]));        //24
     NSLog(@"stu - %zd", malloc_size((__bridge const void *)stu));       //32
    }    
    return 0;
    

    }

2. 对象的isa指针指向哪里

  • instance对象的isa ---> class对象
  • class对象的isa --->  meta-class对象
  • meta-class对象的isa ---> 基类meta-class对象

3.OC的类信息存放在哪里

  • 属性,对象方法,成员变量,协议信息 存放在 class对象中

  • 类方法 存放在 meta-class对象中

  • 成员变量的具体值 存放在 instance对象中

KVO

KVO的实现机制是isa-swizzling。

1.什么是KVO?

KVO是一种基于KVC实现的观察者模式。当指定的被观察的对象的属性更改了,KVO会以自动或手动方式通知观察者。

 事例:监听 ScrollView 的 contentOffSet属性

 [scrollview addObserver:self forKeyPath:@"contentOffset" options:NSKeyValueObservingOptionNew context:nil];

2.KVO的底层实现?(KVO的本质?)(iOS用什么方式实现对一个对象的健值观察?)

1.当给A类addObserver的时候,系统利用RuntimeAPI动态生成一个A类的子类NSKVONotifying_A,让A类实例对象的isa指针指向NSKVONotifying_A类,重写class方法,隐藏对象真实类信息 ([A class]还是A,而不是NSKVONotifying_A)

2.重写监听属性的setter方法

 a) 首先会调用 willChangeValueForKey 

 b) 然后给属性赋值(原来的setter实现) 

 c) 最后调用 didChangeValueForKey(didChangeValueForKey中调用 observer 的 observeValueForKeyPath 去告诉监听器属性值发生了改变 . )

4.重写了dealloc做一些 KVO 内存释放

(removeObserver方法将isa再指向原来的A类)

3.如何手动触发KVO?

手动调用willChangeValueForKey:和didChangeValueForKey:(两个方法缺一不可)

4.添加observer后,直接修改成员变量会触发KVO么?

不会触发KVO(a.xxx = 123 会触发,因为通过属性修改本质是调用的setter方法,而a->xxx = 123不会调用setter方法 所以不会触发KVO)

所以KVO的本质就是在setter方法的实现中加了个观察者

KVC

KVC取值和赋值的过程(原理)

先找setter方法(getter方法),如果没找到就会直接查找成员变量(优先找下划线开头,然后is开头),如果还没找到就抛出异常(UnderfineKey)

Category和Extension (分类和扩展)

blog.csdn.net/u013602835/…

Category的实现原理

Category编译之后的底层结构是struct category_t,里面存储着分类的对象方法、类方法、属性、协议信息

在程序运行的时候,runtime会将Category的数据,合并到类信息中(类对象、元类对象中)

Category和Extension的区别是什么?

他俩本质上就不是一个东西

  • extension在编译期将其内容合并入类,它就是类的一部分,但是category则完全不一样,它是在运行时把数据合入到类对象中的。

    extension在编译期和头文件里的@interface以及实现文件里的@implement一起形成一个完整的类,它、extension伴随类的产生而产生,亦随之一起消亡。

  • extension一般用来隐藏类的私有信息,你必须有一个类的源码才能为一个类添加extension,所以你无法为系统的类比如NSString添加extension,除非创建子类再添加extension。而category不需要有类的源码,我们可以给系统提供的类添加category。

  • extension可以添加实例变量,而category是无法添加实例变量的(因为在运行期,对象的内存布局已经确定,如果添加实例变量就会破坏类的内部布局,这对编译型语言来说是灾难性的)。

  • extension和category都可以添加属性,但是category的属性不能生成成员变量和getter、setter方法的实现。

Category 的 load 和 initialize

www.jianshu.com/p/b5492c40f…

load:

initialize:

Category能否添加成员变量?如果可以,如何给Category添加成员变量?

  • 不能直接给Category添加成员变量,但是可以间接实现Category有成员变量的效果

  • 默认情况下,因为分类底层结构的限制,不能添加成员变量到分类中。但可以通过**关联对象(objc_setAssociatedObject)**来间接实现

  • 关联对象并不是存储在被关联对象本身内存中

  • 关联对象存储在全局的统一的一个AssociationsManager

Block

1.block的本质是什么?

Block本质上是封装了函数调用及函数调用环境OC对象

2.__block

3.block属性形式词是什么?为什么?

4.block循环引用,提前释放?

在和GCD一起使用的时候中间就有个很大的坑,因为block中对对象是弱引用,在block中使用GCD的话,在GCD中使用的对象就是已经弱化的对象,所以会导致这个对象还没开始使用就已经被释放,这时就可以引入__strong来解决。

runtime

juejin.im/post/684490…

juejin.im/post/684490…