美文网首页
iOS基础 4.0

iOS基础 4.0

作者: 脚踏实地的小C | 来源:发表于2023-11-20 16:48 被阅读0次

    前言

    什么是内存对齐,内存对齐规则是什么样的?
    class_getInstanceSize,malloc_size,sizeof区别?
    实例(instance)对象,类(class)对象,元类(meta-class)对象的区别与关系?在内存中各自存储哪些信息?
    class_rw_t,class_ro_t分别包含哪些信息,为什么这么设计?
    isKindOfClass和isMemberOfclass的区别?
    

    11、什么是内存对齐,内存对齐规则是什么样的?

      内存对齐是计算机体系结构中的一个概念,指的是数据在内存中的存储位置相对于内存起始地址的偏移量必须是特定值的倍数。内存对齐的目的是 优化内存访问的效率,因为许多计算机体系结构要求数据按照一定的对齐规则存储,这样可以提高内存访问的速度
      在iOS中,一般使用的是ARM架构,其内存对齐规则通常遵循CPU架构的规范。以下是一些内存对齐的基本规则:

    1、基本类型的对齐

    • char类型通常对齐为1字节
    • short类型通常对齐为2字节
    • int类型通常对齐为4字节
    • long类型通常对齐为4或8字节,取决于平台(32位或64位)
    • float类型通常对齐为4字节
    • double类型通常对齐为8字节

    2、结构体的对齐

    • 结构体的对齐要求是其成员变量中最大对齐要求的成员的对齐要求。(类似想在书架上按规则摆放书籍,你只能以书架的排列规则为要求去对齐)
    • 结构体的总大小需要是最大对齐要求的成员大小的整数倍
    struct ExampleStruct {
        char a;      // 1 字节
        int b;       // 4 字节 (对齐到 4 字节边界)
        double c;    // 8 字节 (对齐到 8 字节边界)
    };
    

      从这个结构体中因为charint所占大大小为1+4=5字节,5+8=13>8字节,这里一个最多只能放8字节,所以就得额外再开辟一个8字节的,所以总的大小是8+8=16字节,是最大的2倍。

    3、指针的对齐
    指针的对齐要求通常和平台相关,iOS上一般为4或8字节,取决于平台(32位或64位)

    12、class_getInstanceSize,malloc_size,sizeof区别?

    这几个都是用于获取对象大小的相关函数,不过在一些方面有区别,下面是它们的主要区别:
    1、class_getInstanceSize

    • 用途:用于获取一个类的实例的大小,即对象内存中所占用字节数。
    • 返回值:返回的是类的实例的大小,不包括关联的额外内存(如关联对象等)。
    • 生活中的比喻:你是一位建筑师,要设计一个独特的办公楼。你想知道这个楼的总体积,而不考虑里面会有哪些办公室和设备
    #import <objc/runtime.h>
    
    Class myClass = [MyClass class];
    size_t instanceSize = class_getInstanceSize(myClass);
    NSLog(@"Instance size of MyClass: %zu", instanceSize);
    

    2、malloc_size

    • 用途:用于获取由malloc分配的内存块的大小。
    • 返回值:返回的是分配的内存块的实际大小,包括可能由于内存对齐而引起的额外字节。
    • 生活中的比喻:你是一个施工队的领导,负责建造一个办公楼。你想知道整个建筑的总体积,包括内部所有的房间设备管道等,以及建筑本身的结构空间
    #include <malloc/malloc.h>
    
    MyClass *myObject = [[MyClass alloc] init];
    size_t size = malloc_size((__bridge const void *)myObject);
    NSLog(@"Size of allocated memory block: %zu", size);
    

    3、sizeof

    • 用途sizeof是C语言的一个关键字,用于获取数据类型或变量的大小。
    • 返回值:返回的是数据类型或变量的大小,不考虑对象内部可能包含的额外信息。
    • 生活中的比喻:你是一位室内设计师,负责设计办公楼里的每个房间。你只关心每个房间大小摆放家具的空间,而不考虑整个楼的结构。
    MyClass *myObject = [[MyClass alloc] init];
    size_t size = sizeof(*myObject);
    NSLog(@"Size of MyClass instance: %zu", size);
    

    13、实例(instance)对象,类(class)对象,元类(meta-class)对象的区别与关系?在内存中各自存储哪些信息?

    1、实例(instance)对象:是类的具体实例,存储了实例变量和方法的具体实现。

    @interface MyClass : NSObject
    @property (nonatomic, assign) int myVariable;
    - (void)myMethod;
    @end
    
    @implementation MyClass
    - (void)myMethod {
        NSLog(@"Executing myMethod");
    }
    @end
    
    // 创建实例对象
    MyClass *myObject = [[MyClass alloc] init];
    [myObject myMethod]; // 调用实例方法
    

    在内存中,实例对象存储了myVariable实例变量的值和myMethod方法的实现。

    2、类(class)对象:描述类的对象,存储了类方法的实现实例变量的布局信息父类指针

    // 获取类对象
    Class myClass = [MyClass class];
    
    // 调用类方法
    [MyClass myClassMethod];
    

    3、元类(meta-class)对象描述类对象的对象,存储了类方法的实现类变量的布局信息。每个类对象都有一个对应的元类对象,而元类对象本身也是一个类对象,它继承父类的元类对象。

    // 获取元类对象
    Class metaClass = object_getClass([MyClass class]);
    
    // 调用类方法
    [metaClass myClassMethod];
    

    关系

    • 实例对象具体实例,存储了实例变量实例方法的实现。
    • 类对象描述类的结构行为,存储了类方法的实现实例变量的布局信息指向父类的指针
    • 元类对象描述类对象的结构行为,存储了类方法的实现类变量的布局信息指向父类的指针。每个类对象都有一个对应的元类对象,而元类对象本身也是一个类对象,它继承自父类的元类对象。

    生活中的比喻

    • 一本具体的书籍(实例对象):你在图书馆中找到一本书,这本书就是一个实例对象。它有自己的内容(实例变量)和功能(方法)

    • 图书馆的书库目录(类对象):图书馆有一个书库目录,它描述了所有书籍的共同特征,比如它们所在的分类、借阅规则等。这个目录就相当于类对象,它包含了描述书籍结构和规则的信息。

    • 图书馆管理员的手册(元类对象):图书馆管理员有一个手册,里面记录了所有图书馆管理员的共同工作规范、培训资料等。这个手册就相当于元类对象,它描述了图书管理员的结构和规则。每个管理员都有一个对应的手册,而手册本身也是一个集合,继承了所有管理员手册的通用规范。

    14、class_rw_t,class_ro_t分别包含哪些信息,为什么这么设计?

      class_rw_t(类的读写部分)和class_ro_t(类的只读部分)是用于描述类信息的两个结构体。这种设计的目的是为了在运行时提供灵活性效率

    class_rw_t(读写部分):包含了类的读写信息,这些信息可能在运行时发生变化,例如在类的扩展中添加了方法

    • uint32_t flag:一些标志,包含了类的一些状态信息。
    • uint32_t version:类的版本号,用于检测类的变化
    • const class_ro_t *ro:执行对应的class_ro_t结构体的指针,指向只读部分的信息。
    • struct method_list **method_lists:类的实例方法列表,可能包含了类的扩展中的方法。
    • struct property_list *properties:类的属性列表

    class_ro_t(只读部分):包含了类的只读信息,这些信息在类的生命周期中基本上是不变的。

    • const char *name:类的名称
    • const struct class *baseClass:父类
    • uintptr_t instanceSize:实例对象的大小
    • uintptr_t info:类信息标志,包含了一些类的特性,比如是否是元类。
    • const struct ivar_list *ivars:实例变量列表
    • const struct method_list *baseMethods:类的实例方法列表
    • const struct protocol_list *baseProtocols:类实现的协议列表

    15、isKindOfClass和isMemberOfclass的区别?

    1、isKindOfClass

    • 定义:判断对象是否属于指定类或其子类
    • 使用场景:通常用于检测对象的类型是否符合某个类或其派生类
    • 使用- (BOOL)isKindOfClass:(Class)aClass;

    2、isMemberOfClass

    • 定义:判断对象是否属于指定类,而不包括其子类
    • 使用场景:用于检测对象的确切类型是否为指定的类
    • 方法-(BOOL)isMemberOfClass:(Class)aClass;
    @interface Animal : NSObject
    @end
    
    @implementation Animal
    @end
    
    @interface Mammal : Animal
    @end
    
    @implementation Mammal
    @end
    
    @interface Bird : Animal
    @end
    
    @implementation Bird
    @end
    
    int main() {
        @autoreleasepool {
            // 创建对象实例
            Animal *animal = [[Animal alloc] init];
            Mammal *mammal = [[Mammal alloc] init];
            Bird *bird = [[Bird alloc] init];
    
            // 使用 isKindOfClass
            if ([animal isKindOfClass:[Animal class]]) {
                NSLog(@"animal 是 Animal 类或其子类");
            }
    
            if ([mammal isKindOfClass:[Animal class]]) {
                NSLog(@"mammal 是 Animal 类或其子类");
            }
    
            if ([bird isKindOfClass:[Animal class]]) {
                NSLog(@"bird 是 Animal 类或其子类");
            }
    
            // 使用 isMemberOfClass
            if ([animal isMemberOfClass:[Animal class]]) {
                NSLog(@"animal 是 Animal 类");
            }
    
            if ([mammal isMemberOfClass:[Animal class]]) {
                NSLog(@"mammal 是 Animal 类");
            }
    
            if ([bird isMemberOfClass:[Animal class]]) {
                NSLog(@"bird 是 Animal 类");
            }
        }
        return 0;
    }
    
    //打印:
    animal 是 Animal 类或其子类
    mammal 是 Animal 类或其子类
    bird 是 Animal 类或其子类
    animal 是 Animal 类
    

      通过这个示例,我们可以看到,在isKindOfClass的使用中mammalbird都会返回YES,因为它们是Animal类的子类。而在isMemberOfClass的使用中,mammalbird都会返回NO,因为它不是严格的Animal类的实例。

    相关文章

      网友评论

          本文标题:iOS基础 4.0

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