阅读 128

iOS开发:Runtime面试题合集(二)

1、使用runtime Associate方法关联的对象,需要在主对象dealloc的时候释放么?

无论在MRC下还是ARC下均不需要,被关联的对象在生命周期内要比对象本身释放的晚很多,它们会在被 NSObject -dealloc 调用的object_dispose()方法中释放。

详解:

1、调用 -release :引用计数变为零
对象正在被销毁,生命周期即将结束. 
不能再有新的 __weak 弱引用,否则将指向 nil.
调用 [self dealloc]

2、 父类调用 -dealloc 
继承关系中最直接继承的父类再调用 -dealloc 
如果是 MRC 代码 则会手动释放实例变量们(iVars)
继承关系中每一层的父类 都再调用 -dealloc

>3、NSObject 调 -dealloc 
只做一件事:调用 Objective-C runtime 中object_dispose() 方法

>4. 调用 object_dispose()
为 C++ 的实例变量们(iVars)调用 destructors
为 ARC 状态下的 实例变量们(iVars) 调用 -release 
解除所有使用 runtime Associate方法关联的对象 
解除所有 __weak 引用 
调用 free()
复制代码

2、实例对象的数据结构?

具体可以参看 Runtime 源代码,在文件 objc-private.h 的第 127-232 行。

struct objc_object {
	isa_t isa;
	//...
}
复制代码

本质上 objc_object 的私有属性只有一个 isa 指针。指向 类对象 的内存地址。

3、什么是method swizzling(俗称黑魔法)

简单说就是进行方法交换

在Objective-C中调用一个方法,其实是向一个对象发送消息,查找消息的唯一依据是selector的名字。利用Objective-C的动态特性,可以实现在运行时偷换selector对应的方法实现,达到给方法挂钩的目的。 每个类都有一个方法列表,存放着方法的名字和方法实现的映射关系,selector的本质其实就是方法名,IMP有点类似函数指针,指向具体的Method实现,通过selector就可以找到对应的IMP。 换方法的几种实现方式

  • 利用 method_exchangeImplementations 交换两个方法的实现
  • 利用 class_replaceMethod替换方法的实现
  • 利用 method_setImplementation 来直接设置某个方法的IMP

4、什么时候会报unrecognized selector的异常?

objc在向一个对象发送消息时,runtime库会根据对象的isa指针找到该对象实际所属的类,然后在该类中的方法列表以及其父类方法列表中寻找方法运行,如果,在最顶层的父类中依然找不到相应的方法时,会进入消息转发阶段,如果消息三次转发流程仍未实现,则程序在运行时会挂掉并抛出异常unrecognized selector sent to XXX 。

5、何给 Category 添加属性?关联对象以什么形式进行存储?

查看的是 关联对象 的知识点。

详细的说一下 关联对象

关联对象 以哈希表的格式,存储在一个全

局的单例中。

@interface NSObject (Extension)

@property (nonatomic,copy  ) NSString *name;

@end


@implementation NSObject (Extension)

- (void)setName:(NSString *)name {
    
    objc_setAssociatedObject(self, @selector(name), name, OBJC_ASSOCIATION_COPY_NONATOMIC);
}


- (NSString *)name {
    
    return objc_getAssociatedObject(self,@selector(name));
}

@end
复制代码

6、能否向编译后得到的类中增加实例变量?能否向运行时创建的类中添加实例变量?为什么?

不能向编译后得到的类中增加实例变量;

能向运行时创建的类中添加实例变量;

1.因为编译后的类已经注册在 runtime 中,类结构体中的 objc_ivar_list 实例变量的链表和 instance_size 实例变量的内存大小已经确定,同时runtime会调用 class_setvarlayout 或 class_setWeaklvarLayout 来处理strong weak 引用.所以不能向存在的类中添加实例变量。 2.运行时创建的类是可以添加实例变量,调用class_addIvar函数. 但是的在调用 objc_allocateClassPair 之后,objc_registerClassPair 之前,原因同上.

7、类对象的数据结构?

具体可以参看 Runtime 源代码。

类对象就是 objc_class

struct objc_class : objc_object {
    // Class ISA;
    Class superclass; //父类指针
    cache_t cache;             // formerly cache pointer and vtable 方法缓存
    class_data_bits_t bits;    // class_rw_t * plus custom rr/alloc flags 用于获取地址

    class_rw_t *data() { 
        return bits.data(); // &FAST_DATA_MASK 获取地址值
    }
复制代码

它的结构相对丰富一些。继承自objc_object结构体,所以包含isa指针

  • isa:指向元类
  • superClass: 指向父类
  • Cache: 方法的缓存列表
  • data: 顾名思义,就是数据。是一个被封装好的 class_rw_t

那些 iOS开发 常用的底层面试题合集!