美文网首页
Objective-C面试资料整理

Objective-C面试资料整理

作者: 洋_iOS | 来源:发表于2020-05-08 13:20 被阅读0次

    Objective-C的本质

    Objective-C -> C/C++  -> 汇编语言 ->机器语言
    

    Objective-C 简单转换 C\C++代码(代码比较多)

    clang -rewrite-objc main.m -o main.cpp
    

    转换成对应平台下cpp文件
    模拟器(i386, x86-64) 32bit(armv7) 64bit(arm64)

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

    Objective-C的面向对象都是基于C\C++实现的,本质是结构体.

    @interface NSObject <NSObject> {
        Class isa;
    }
    
    struct NSObject_IMPL {
        Class isa;
    };
    
    typedef struct objc_class *Class;
    

    至少需要多少内存(计算结构体内存大小)

    class_getInstanceSize([NSObject class]) // 8
    

    实际分配内存大小(操作系统内存对齐)

    malloc_size((__bridge const void *)([[NSObject alloc] init])) // 16
    

    指针变量obj占用多少内存空间

    NSObject *obj = [[NSObject alloc] init];
    sizeof(obj); //8
    

    Objective-C的分类

    instance对象(实例对象)

    obj是NSObject的instance对象(实例对象)
    NSObject *obj = [[NSObject alloc] init];
    
    instance对象在内存中存储信息主要包括
     isa指针
     其他成员变量
     ......
    

    class对象(类对象)

    objClass1,objClass2,objClass3是同一个对象,每个类有且只有一个类对象
    Class objClass1 = [obj class];
    Class objClass2 = [NSObject class];
    Class objClass3 = object_getClass(obj);
    
    class对象在内存中存储信息主要包括
    isa指针
    superClass指针
    类的属性(@property),类的对象方法(instance method)
    类的协议(protocol),类的成员变量(ivar)
    ......
    

    meta-class对象(元类对象)

    objMetaClass是NSObject的元类对象,每个类有且只有一个元类对象
    Class objMetaClass = object_getClass([NSObject class]);
    
    是否是元类对象
    BOOL isMeta = class_isMetaClass(objMetaClass);
    
    元类对象是特殊的类对象
    
    meta-class对象在内存中存储信息主要包括
    isa指针
    superClass指针
    类的类方法(class method)
    ......
    

    isa指针和superClass指针

    instance对象 isa -> class对象 -> meta-class对象 -> 基类的meta-class对象
    class的superClass -> 父类的class(若是空,superClass是nil)

    meta-class的superClass -> 父类的meta-class
    基类的meta-class的superClass -> 基类的class

    instance调用对象方法路径: isa找到class,若不存在,通过superClass找父类
    class调用类方法路径:isa找meta-class,若不存在,通过superClass找父类

    isa和superClass.png

    isa指针

    从64位开始优化,需要&ISA_MASK
    instance的 isa & ISA_MASK 得到 class的isa
    class的 isa & ISA_MASK 得到 meta-class 的isa

    objc4源码查看 https://opensource.apple.com/tarballs/objc4/

    typedef struct objc_class *Class;
    struct objc_class {
        Class isa;
        Class superClass;
        cache_t cache;           //方法缓存
        class_data_bits_t bits;  //用于获取具体的类信息
        ......
    };
    
    bits & FAST_DATA_MASK 得到 class_rw_t
    
    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;
        ......
    };
    
    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;
        method_list_t *baseMethods() const {
            return baseMethodList;
        }
    };
    
    
    

    KVO的全称是Key-Value Observing,俗称“键值监听”,可以用于监听某个对象属性值的改变
    KVO代码层面使用

    //添加监听属性
    - (void)addKVOTest {
        self.kvo = [[KVOTest alloc] init];
        NSKeyValueObservingOptions options = NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld;
        [self.kvo addObserver:self forKeyPath:@"age" options:options context:@"123"];
    }
    
    //合适时机销毁
    - (void)dealloc {
        [self.kvo removeObserver:self forKeyPath:@"age"];
    }
    //监听属性的变化
    - (void)observeValueForKeyPath:(NSString *)keyPath
                          ofObject:(id)object
                            change:(NSDictionary<NSKeyValueChangeKey,id> *)change
                           context:(void *)context {
        
        NSLog(@"监听到%@的%@属性值改变了 - %@ - %@", object, keyPath, change, context);
    }
    

    KVO底层原理:
    使用KVO监听后,runtime会动态创建一个 NSKVONotifying_监听类,是监听类的子类
    调用方法顺序
    willChangeValueForKey:
    setAge: ( Foundation下_NSSetIntValueAndNotify() )
    observerValueForKey
    didChangeValueForKey:

    KVC的全称是Key-Value Coding,俗称“键值编码”,可以通过一个key来访问某个属性

    • (void)setValue:(id)value forKeyPath:(NSString *)keyPath;
    • (void)setValue:(id)value forKey:(NSString *)key;
    • (id)valueForKeyPath:(NSString *)keyPath;
    • (id)valueForKey:(NSString *)key;

    setValueForKey的流程
    1、按照setKey、_setKey顺序查找方法, 找到了直接调用方法
    2、如果找不到,查看accessInstanceVariablesDirectly(能否直接访问成员变量)的返回值,
    NO,直接报错 setValue:forUndefinedKey:,
    YES,通过_key, _isKey, key, isKey顺序查找成员变量,找到了直接赋值,都找不到直接报错 setValue:forUndefinedKey:

    valueForKey的流程
    1、按照getKey、Key、isKey、_key的顺序查找方法,找到直接调用
    2、如果找不到,查看accessInstanceVariablesDirectly(能否直接访问成员变量)的返回值,
    NO,直接报错 setValue:forUndefinedKey:,
    YES,通过_key, _isKey, key, isKey顺序查找成员变量,找到了直接取值,都找不到直接报错 setValue:forUndefinedKey:

    Category

    分类的底层结构
    终端输入

    xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc NSObject+FenLeiTest.m

    struct _category_t {
        const char *name;
        struct _class_t *cls;
        const struct _method_list_t *instance_methods;
        const struct _method_list_t *class_methods;
        const struct _protocol_list_t *protocols;
        const struct _prop_list_t *properties;
    };
    

    1、通过Runtime加载某个类的所有Category数据
    2、把所有Category的方法、属性、协议数据,合并到一个大数组中
    后面参与编译的Category数据,会在数组的前面
    3、将合并后的分类数据(方法、属性、协议),插入到类原来数据的前面

    相关文章

      网友评论

          本文标题:Objective-C面试资料整理

          本文链接:https://www.haomeiwen.com/subject/cekfnhtx.html