Runtime¶
给我讲一下 iOS runtime
iOS runtime 是 Apple 提供的一个底层框架,用于支持 Objective-C 语言的动态特性。它是 Objective-C 编译后的核心库,负责实现动态方法调用、消息传递、动态类型检查、动态加载类和对象的内存管理等功能。了解 iOS runtime 对于深入理解和优化 iOS 应用程序至关重要。以下是 iOS runtime 的一些关键概念和功能:
1. 动态类型与消息传递¶
在 Objective-C 中,方法调用被称为“消息传递”。每个方法调用实际上是向对象发送一条消息。例如,调用 [object doSomething]
实际上是发送消息 doSomething
给 object
。这种机制使得程序在运行时可以决定调用哪个方法。
2. 方法与消息¶
Objective-C 的方法调用是通过消息传递机制实现的,objc_msgSend
是最常用的消息传递函数。方法的具体实现被动态地绑定到消息上。方法选择器(selector)是方法名的唯一标识符,通常是 SEL
类型。
3. 动态方法解析¶
当一个对象接收到一个无法识别的消息时,runtime 会提供机会动态解析这个方法。可以通过实现 +(BOOL)resolveInstanceMethod:(SEL)sel
或 +(BOOL)resolveClassMethod:(SEL)sel
来动态添加方法实现。
4. 消息转发¶
如果一个对象无法处理某个消息,可以通过消息转发机制将消息转发给其他对象。实现 - (id)forwardingTargetForSelector:(SEL)aSelector
或 - (void)forwardInvocation:(NSInvocation *)anInvocation
方法可以处理无法识别的消息。
5. 类与元类¶
在 runtime 中,每个类(class)本身也是一个对象。每个类都有一个指向其元类(metaclass)的指针,元类定义了类方法的实现。实例方法保存在类对象中,类方法保存在元类对象中。
6. 动态特性¶
Objective-C 允许在运行时动态创建类、添加方法、交换方法实现等。这使得开发者可以实现一些灵活的功能,如方法调配(method swizzling)和动态代理(dynamic proxies)。
7. 内存管理¶
iOS runtime 负责对象的内存管理,包括引用计数和自动释放池(autorelease pool)的实现。ARC(Automatic Reference Counting)是编译器特性,但背后依赖 runtime 提供的内存管理功能。
8. Associated Objects¶
可以使用 runtime 动态地将属性关联到对象上。这是通过 objc_setAssociatedObject
和 objc_getAssociatedObject
函数实现的。它使得开发者可以在不修改类定义的情况下,向对象添加新的属性。
常用的 runtime 函数¶
class_getName
:获取类名class_getInstanceMethod
:获取实例方法class_getClassMethod
:获取类方法method_getImplementation
:获取方法的实现method_setImplementation
:设置方法的实现objc_allocateClassPair
:创建新类objc_registerClassPair
:注册新创建的类
示例代码¶
以下是一个简单示例,展示了如何使用 runtime 动态添加方法:
#import <objc/runtime.h>
#import <Foundation/Foundation.h>
void dynamicMethodIMP(id self, SEL _cmd) {
NSLog(@"This is a dynamically added method.");
}
int main(int argc, const char * argv[]) {
@autoreleasepool {
// 动态创建一个类
Class DynamicClass = objc_allocateClassPair([NSObject class], "DynamicClass", 0);
// 动态添加方法
class_addMethod(DynamicClass, @selector(dynamicMethod), (IMP)dynamicMethodIMP, "v@:");
// 注册类
objc_registerClassPair(DynamicClass);
// 创建类实例
id instance = [[DynamicClass alloc] init];
// 调用动态添加的方法
[instance performSelector:@selector(dynamicMethod)];
}
return 0;
}
这个示例展示了如何动态创建一个类并向其添加方法,以及如何调用这个动态添加的方法。
iOS runtime 提供了强大的动态特性,使得 Objective-C 语言能够灵活高效地实现各种功能。理解并善用这些特性,对于开发高效、灵活的 iOS 应用至关重要。
objc_object, objc_class, isa 指针,method_t 这些都是什么,解释一下,还有实际用处
在 Objective-C 的 runtime 系统中,objc_object
、objc_class
、isa
指针和 method_t
是一些核心概念和结构体,它们在实现动态特性和面向对象机制中起着重要作用。下面分别解释这些概念及其实际用处。
1. objc_object
¶
objc_object
是 Objective-C 中所有对象的基类,实际上是一个包含 isa
指针的结构体。这个 isa
指针指向对象的类。
struct objc_object {
Class isa;
};
2. objc_class
¶
objc_class
是描述类的结构体。它本质上也是一个 objc_object
,因此包含 isa
指针。一个类的 isa
指针指向它的元类(metaclass)。
struct objc_class {
Class isa; // 指向元类
Class super_class; // 指向父类
const char *name; // 类名
long version;
long info;
long instance_size;
struct objc_ivar_list *ivars; // 成员变量列表
struct objc_method_list **methodLists; // 方法列表
struct objc_cache *cache; // 方法缓存
struct objc_protocol_list *protocols; // 协议列表
};
3. isa
指针¶
isa
指针是每个 objc_object
和 objc_class
都包含的一个指针。它是 runtime 系统中用于实现动态类型和消息传递机制的关键。
- 对于实例对象,
isa
指针指向它的类(objc_class
)。 - 对于类对象,
isa
指针指向它的元类(metaclass)。 - 元类的
isa
指针最终指向NSObject
的元类,形成一个闭环。
isa
指针的作用包括:
- 用于确定对象的类型。
- 用于查找对象的方法实现。
4. method_t
¶
method_t
是一个描述方法的结构体,包含方法的选择器(selector)、方法实现(IMP)和方法类型编码(type encoding)。
struct method_t {
SEL name; // 方法选择器
const char *types; // 方法类型编码
IMP imp; // 方法实现
};
实际用处¶
理解这些结构体和指针在实际开发中有多种用处:
动态类型与消息传递¶
isa
指针是实现动态类型检查和消息传递的关键。当一个对象接收到消息时,runtime 系统通过 isa
指针找到对象的类,然后在类的方法列表中查找对应的 method_t
结构体,找到方法实现并调用。
方法调配(Method Swizzling)¶
开发者可以使用 runtime 方法交换技术(method swizzling)来替换类的方法实现,从而在不修改原始代码的情况下添加或修改功能。这在调试、日志记录、AOP(面向切面编程)等方面非常有用。
void MethodSwizzle(Class c, SEL origSEL, SEL newSEL) {
Method origMethod = class_getInstanceMethod(c, origSEL);
Method newMethod = class_getInstanceMethod(c, newSEL);
method_exchangeImplementations(origMethod, newMethod);
}
动态添加方法¶
开发者可以在运行时动态向类添加方法,增强类的功能。例如,可以通过 class_addMethod
函数添加新的方法。
BOOL class_addMethod(Class cls, SEL name, IMP imp, const char *types);
动态创建类¶
可以在运行时动态创建新的类,满足某些动态需求。例如,根据不同的运行时环境创建不同的类实现。
Class newClass = objc_allocateClassPair([NSObject class], "DynamicClass", 0);
objc_registerClassPair(newClass);
Associated Objects¶
通过 objc_setAssociatedObject
和 objc_getAssociatedObject
函数,开发者可以动态地将任意数据关联到现有对象上,扩展对象的功能而无需修改类定义。
objc_setAssociatedObject(object, @selector(property), value, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
id value = objc_getAssociatedObject(object, @selector(property));
总结¶
了解 objc_object
、objc_class
、isa
指针和 method_t
结构体对深入理解 iOS runtime 系统至关重要。这些概念帮助开发者掌握动态类型、消息传递、方法调配等高级特性,使得开发者能够创建更灵活和强大的 iOS 应用程序。
对象的 isa 指向类,类的 isa 指向元类? 类中存放对象的方法,也就是那些减号方法,元类中存放类的方法 也就是那些加号方法,理解的对么
是的,你的理解是正确的。下面我详细解释一下这一点:
1. isa
指针的层次结构¶
- 对象(Instance Object):
-
对象的
isa
指针指向它所属的类(objc_class
)。 -
类(Class):
- 类的
isa
指针指向元类(Metaclass)。 -
类中存储实例方法(即以
-
开头的方法)。 -
元类(Metaclass):
- 元类的
isa
指针指向根元类(Root Metaclass),通常是NSObject
的元类。 -
元类中存储类方法(即以
+
开头的方法)。 -
根元类(Root Metaclass):
- 根元类的
isa
指针指向自身,形成一个闭环。
2. 层次结构图示¶
+----------------------+
| Root Metaclass |
+----------------------+
| +classMethod |
isa +-------------------------------+ isa
+----> | isa指向自身 |
| +-------------------------------+
|
+----v----------------+
| Metaclass |
+---------------------+
| +classMethod |
+---------------------+
isa +-------------------------------+ isa
+----> | isa指向Root Metaclass |
| +-------------------------------+
|
+----v----------------+
| Class |
+---------------------+
| -instanceMethod |
+---------------------+
isa +-------------------------------+ isa
+----> | isa指向Metaclass |
+-------------------------------+
|
+--------------v--------------+
| Instance Object |
+-----------------------------+
| isa指向Class |
+-----------------------------+
3. 方法存储¶
- 实例方法(Instance Methods):
- 定义在类对象中,以
-
开头。 - 这些方法是实例对象可以调用的方法。
-
例如,
- (void)instanceMethod
。 -
类方法(Class Methods):
- 定义在元类对象中,以
+
开头。 - 这些方法是类本身可以调用的方法。
- 例如,
+ (void)classMethod
。
实际例子¶
假设有一个类 MyClass
,并且它有一个实例方法 - (void)instanceMethod
和一个类方法 + (void)classMethod
。
- 实例对象:
MyClass *myObject = [[MyClass alloc] init];
-
myObject
的isa
指针指向MyClass
。 -
类对象:
-
MyClass
的isa
指针指向它的元类MyClass
的元类。 -
元类对象:
-
MyClass
的元类的isa
指针指向根元类NSObject
的元类。 -
方法存储:
MyClass
中存储了- (void)instanceMethod
,所以myObject
可以调用[myObject instanceMethod]
。MyClass
的元类中存储了+ (void)classMethod
,所以MyClass
可以调用[MyClass classMethod]
。
总结¶
你的理解是正确的,实例方法存储在类中,类方法存储在元类中。isa
指针层次结构确保了在运行时能够正确地找到并调用这些方法。这种设计使得 Objective-C 的动态特性和消息传递机制能够有效运作。
id = objc_object 吗
在 Objective-C 中,id
是一种特殊的类型,它可以表示任何类型的对象。尽管在底层实现中 id
的确是与 objc_object *
相关联的,但它们并不完全相同。
id
类型¶
- 定义:
id
是一种通用的对象指针类型。它可以指向任何 Objective-C 对象。 - 特点:
id
类型的变量是动态类型的,也就是说,编译器不会检查id
类型变量所指向对象的具体类型。可以调用任何对象的方法,具体的类型检查和方法调用在运行时进行。
objc_object
结构体¶
- 定义:
objc_object
是 Objective-C runtime 用来表示对象的结构体。 - 结构:
objc_object
结构体至少包含一个指向类的isa
指针。实际上,Objective-C 的每个对象在底层都是objc_object
类型的。
struct objc_object {
Class isa;
};
id
和 objc_object *
的关系¶
- 在底层,
id
实际上是一个指向objc_object
结构体的指针,也就是说id
可以被看作objc_object *
类型。 - 由于
id
是通用的对象类型,它可以表示任何继承自objc_object
的对象,包括自定义的 Objective-C 类实例。
示例¶
id obj = [[NSObject alloc] init];
在这段代码中,obj
是一个 id
类型的变量,它指向一个 NSObject
的实例。底层实现中,这个 NSObject
实例是一个 objc_object
结构体,并且 obj
实际上是一个指向 objc_object
结构体的指针。
小结¶
id
是一个可以表示任何 Objective-C 对象的通用指针类型。objc_object
是 Objective-C runtime 用来表示对象的底层结构体。- 从技术角度看,
id
可以被认为是objc_object *
类型,但它提供了更多的灵活性,因为它可以指向任何类型的对象而无需编译时类型检查。
这种设计使得 Objective-C 具有高度的动态性和灵活性,能够在运行时处理多态对象和消息传递。
我有个问题,你说 objc_object 是 描述对象的结构体,objc_class 是描述类的结构体,对象不是类生成的么,为啥 objc_class 要继承 objc_object 呢?
这是一个非常好的问题,涉及到 Objective-C runtime 系统的设计原理。在 Objective-C 中,对象(instance)、类(class)和元类(metaclass)之间的关系和继承层次有一定的复杂性,这样设计是为了实现面向对象的动态特性和消息传递机制。
对象、类和元类的关系¶
- 对象(Instance):
- 由类生成,每个对象都包含一个
isa
指针,指向它的类。 -
isa
指针用于在运行时确定对象的类型和查找方法的实现。 -
类(Class):
- 描述一组对象的结构和行为。
- 类本身也是一个对象,因此需要一个
isa
指针,指向它的元类。 -
类中存储了实例方法、成员变量等信息。
-
元类(Metaclass):
- 描述类的类,也就是类的结构和行为。
- 元类本身也是一个对象,因此也需要一个
isa
指针,指向根元类。 - 元类中存储了类方法。
为什么 objc_class
继承 objc_object
¶
在 Objective-C 中,类和元类也是对象。为了使类和元类能够参与运行时消息传递机制和动态特性,它们必须具有对象的基本特性。这就是为什么 objc_class
继承自 objc_object
。具体来说:
- 统一的对象模型:
-
在 Objective-C 中,一切都是对象。这包括实例、类和元类。通过让类和元类继承自
objc_object
,确保它们都具有一个isa
指针,从而可以使用相同的机制进行类型判断和消息传递。 -
消息传递机制:
- 消息传递是 Objective-C 的核心机制。对象通过
isa
指针找到它的类,然后在类的方法列表中查找方法实现。同样,类方法的查找需要通过类的isa
指针找到元类,再在元类的方法列表中查找方法实现。
继承层次¶
+----------------------+
| Root Metaclass |
+----------------------+
isa ^ |
| |
+-------+-------+
| Metaclass |
+----------------------+
isa ^ |
| |
+-------+-------+
| Class |
+----------------------+
isa ^ |
| |
+-------+-------+
| Instance Object |
+----------------------+
具体结构¶
-
objc_object
:objective-c struct objc_object { Class isa; };
-
objc_class
(继承自objc_object
):objective-c struct objc_class : objc_object { Class super_class; // 指向父类 const char *name; // 类名 long version; long info; long instance_size; struct objc_ivar_list *ivars; // 成员变量列表 struct objc_method_list **methodLists; // 方法列表 struct objc_cache *cache; // 方法缓存 struct objc_protocol_list *protocols; // 协议列表 };
总结¶
objc_object
是所有对象的基类,包括实例对象、类对象和元类对象。- 通过让
objc_class
继承自objc_object
,确保类和元类也具有对象的特性,可以参与消息传递和动态类型检查。 - 这种设计使得 Objective-C runtime 能够统一处理实例、类和元类,实现灵活的面向对象机制。
通过这种设计,Objective-C 能够提供强大的动态特性,支持灵活的消息传递和运行时类型处理。
objc_object 是 Objective-C 中所有对象的基类,实际上是一个包含 isa 指针的结构体。这个 isa 指针指向对象的类。
这句话 所有对象只的是什么对象,是一个类 alloc init 出来的那个对象么. 你说是所有对象的基类,那 nsobject 是啥
你的问题很有意义,可以帮助深入理解 Objective-C 的对象模型。让我们一起来理清几个概念:
objc_object
和 NSObject
的区别¶
objc_object
:- 定义:
objc_object
是 Objective-C runtime 系统中的基础结构体,它定义了所有 Objective-C 对象的基本结构。 - 内容:这个结构体包含一个
isa
指针,用于指向对象的类。 - 作用:它是 runtime 层面上的基类,所有的 Objective-C 对象在底层都可以被视为
objc_object
类型。
struct objc_object {
Class isa;
};
NSObject
:- 定义:
NSObject
是一个实际存在于代码中的基类,绝大多数 Objective-C 类都是直接或间接继承自NSObject
。 - 作用:它提供了许多基础功能和方法,如对象的初始化、内存管理、方法调用等。
@interface NSObject
// 基本方法和属性定义
@end
所有对象的基类¶
当我们说 objc_object
是所有对象的基类时,这里的“对象”指的是所有通过 alloc
和 init
方法创建出来的实例对象。这些实例对象在底层都是由 objc_object
结构体表示的。
isa
指针的作用¶
每个 objc_object
都有一个 isa
指针,指向它所属的类。通过 isa
指针,runtime 可以在运行时确定对象的类型,并找到相应的方法实现。
NSObject
和 objc_object
的关系¶
NSObject
是一个实际存在的类,定义了许多常用的方法和属性。NSObject
在 runtime 层面上可以看作是 objc_object
的一种扩展。换句话说,NSObject
继承自 objc_object
,虽然这种继承关系在实际代码中不是直接体现的,而是由 Objective-C runtime 系统隐式处理的。
实例对象、类对象和元类对象¶
- 实例对象:
- 通过
alloc
和init
创建的实际对象。 - 例如,
MyClass *obj = [[MyClass alloc] init];
-
obj
是一个实例对象,底层结构是objc_object
,其isa
指针指向MyClass
。 -
类对象:
- 定义实例对象行为的对象。
-
例如,
[MyClass class]
返回MyClass
的类对象,其isa
指针指向MyClass
的元类。 -
元类对象:
- 定义类对象行为的对象。
- 例如,
MyClass
的元类,其isa
指针指向根元类(通常是NSObject
的元类)。
总结¶
objc_object
是一个底层结构体,所有的 Objective-C 对象在底层都是objc_object
类型。NSObject
是一个实际的基类,大多数 Objective-C 类都继承自它,提供了许多基础功能。- 当我们说
objc_object
是所有对象的基类时,是指所有通过alloc
和init
方法创建出来的实例对象在底层都可以被看作objc_object
类型。 isa
指针在对象、类和元类之间建立了关系,使得 Objective-C 能够实现动态消息传递和类型判断。
通过理解这些概念,我们可以更深入地理解 Objective-C 的对象模型和运行机制。
当我们说 objc_object 是所有对象的基类时,是指所有通过 alloc 和 init 方法创建出来的实例对象在底层都可以被看作 objc_object 类型。
这句话,和你上面说的一句话 objc_object 是所有对象的基类,包括实例对象、类对象和元类对象。 类对象通过什么方法获得的,元类对象呢
你提出的问题非常关键,有助于深入理解 Objective-C 的对象模型及其运行时机制。为了进一步澄清,我们需要更详细地探讨类对象和元类对象的获取方式,以及它们在 Objective-C runtime 系统中的地位和关系。
1. objc_object
是所有对象的基类¶
objc_object
是一个底层结构体,是 Objective-C runtime 中所有对象的基类。这包括实例对象、类对象和元类对象。在更具体的层次上:
- 实例对象(Instance Object):通过
alloc
和init
方法创建。 - 类对象(Class Object):表示类本身,是通过消息传递或 runtime 函数获取。
- 元类对象(Metaclass Object):表示类的类,用于存储类方法,同样可以通过 runtime 函数获取。
2. 实例对象、类对象和元类对象的获取方式¶
实例对象的创建¶
实例对象是通过类的 alloc
和 init
方法创建的。
MyClass *instance = [[MyClass alloc] init];
在这个例子中,instance
是一个 MyClass
的实例对象,其 isa
指针指向 MyClass
。
类对象的获取¶
类对象表示类本身,可以通过 [MyClass class]
或 runtime 提供的函数 objc_getClass
获取。
Class classObject = [MyClass class];
// 或者
Class classObject = objc_getClass("MyClass");
在这个例子中,classObject
是 MyClass
的类对象,其 isa
指针指向 MyClass
的元类。
元类对象的获取¶
元类对象表示类的类,可以通过 runtime 提供的函数 object_getClass
获取。
Class metaclassObject = object_getClass([MyClass class]);
在这个例子中,metaclassObject
是 MyClass
的元类对象,其 isa
指针指向根元类(通常是 NSObject
的元类)。
3. 类与元类的层次结构¶
在 Objective-C 中,类对象和元类对象之间有一个层次结构,用于实现消息传递和动态类型检查。以下是一个简单的层次结构图:
+----------------------+
| Root Metaclass |
+----------------------+
^
|
+-------+-------+
| Metaclass |
+----------------------+
^
|
+-------+-------+
| Class |
+----------------------+
^
|
+-------+-------+
| Instance Object |
+----------------------+
- 实例对象 的
isa
指针指向它的类对象。 - 类对象 的
isa
指针指向它的元类对象。 - 元类对象 的
isa
指针指向根元类对象(NSObject
的元类),形成一个闭环。
4. 示例代码¶
以下代码展示了如何获取类对象和元类对象:
#import <objc/runtime.h>
#import <Foundation/Foundation.h>
@interface MyClass : NSObject
@end
@implementation MyClass
@end
int main(int argc, const char * argv[]) {
@autoreleasepool {
// 创建实例对象
MyClass *instance = [[MyClass alloc] init];
// 获取类对象
Class classObject = [MyClass class];
// 获取元类对象
Class metaclassObject = object_getClass(classObject);
// 打印结果
NSLog(@"Instance isa: %s", class_getName(object_getClass(instance)));
NSLog(@"Class isa: %s", class_getName(object_getClass(classObject)));
NSLog(@"Metaclass isa: %s", class_getName(object_getClass(metaclassObject)));
}
return 0;
}
运行结果大致如下:
Instance isa: MyClass
Class isa: MyClass (metaclass)
Metaclass isa: NSObject (metaclass)
总结¶
objc_object
是所有对象的基类,包括实例对象、类对象和元类对象。- 实例对象通过
alloc
和init
方法创建。 - 类对象通过
[MyClass class]
或objc_getClass
函数获取。 - 元类对象通过
object_getClass
函数获取。
理解这些关系和获取方式,有助于更深入地掌握 Objective-C 的运行时机制和面向对象编程模型。
你这个代码例子 对象的 isa 指向的 myclass, myclass 的 isa 指向他的元类,他的元类名字为啥 也叫 myclass
你提到的疑问是关于为什么在日志中打印出的元类的名称也是 MyClass
。这是因为 object_getClass
返回的对象的名称会根据 class_getName
方法返回类的名称,而元类的名称与其对应的类是相同的。
解释 isa
指针和类名称¶
每个实例对象都有一个 isa
指针指向其所属的类对象。类似地,每个类对象也有一个 isa
指针指向其元类对象。元类对象的名称与它所表示的类是相同的,这样设计是为了简化和统一类和元类的处理。
class_getName
函数的作用¶
class_getName
函数用于获取类的名称,无论它是一个类还是元类,都会返回相同的名称。为了进一步澄清这个问题,我们可以调整代码示例,明确区分类对象和元类对象。
详细示例代码¶
#import <objc/runtime.h>
#import <Foundation/Foundation.h>
@interface MyClass : NSObject
@end
@implementation MyClass
@end
int main(int argc, const char * argv[]) {
@autoreleasepool {
// 创建实例对象
MyClass *instance = [[MyClass alloc] init];
// 获取类对象
Class classObject = [MyClass class];
// 获取元类对象
Class metaclassObject = object_getClass(classObject);
// 获取根元类对象
Class rootMetaclassObject = object_getClass(metaclassObject);
// 打印结果
NSLog(@"Instance isa: %s", class_getName(object_getClass(instance)));
NSLog(@"Class name: %s", class_getName(classObject));
NSLog(@"Class isa (Metaclass): %s", class_getName(metaclassObject));
NSLog(@"Metaclass isa (Root Metaclass): %s", class_getName(rootMetaclassObject));
}
return 0;
}
结果分析¶
在这段代码中,我们打印了以下信息:
- 实例对象的
isa
指针: - 指向
MyClass
类。 -
输出:
Instance isa: MyClass
-
类对象的名称:
- 直接获取类对象的名称。
-
输出:
Class name: MyClass
-
类对象的
isa
指针(指向元类对象): - 获取
MyClass
的元类对象。 - 元类对象的名称与其对应的类相同。
-
输出:
Class isa (Metaclass): MyClass
-
元类对象的
isa
指针(指向根元类对象): - 获取
MyClass
元类对象的isa
指针,通常是指向NSObject
的元类。 - 输出:
Metaclass isa (Root Metaclass): NSObject
总结¶
- 类对象和元类对象:在 Objective-C 中,类对象和元类对象的名称是相同的。这是为了统一处理类和元类。
isa
指针:通过isa
指针,实例对象指向其类对象,类对象指向其元类对象,而元类对象通常指向根元类(如NSObject
的元类)。
这样设计使得 Objective-C 运行时能够统一管理对象、类和元类,简化消息传递和类型判断的实现。
好了 我来总结一下,看我说的哪里有问题。 手相 objc_object 是一些对象的基类,包括实例对象,类对象,元类对象。这里所说的基类是继承概念吗,我觉得不是。objc_object 是结构体,是描述所有对象的结构体。objc_class 呢 他是描述类的结构体,同时也继承 objc_object,,对象,类,元类,他们之间靠什么联系呢,就是 这个 isa 指针,这个指针在哪里呢,就在 objc_object 结构体中。
你的总结基本上是正确的,不过有一些细节可以进一步澄清和完善。以下是对你的总结的详细解释和补充:
1. objc_object
是所有对象的基类¶
- 准确性:
objc_object
并不是一个基类,而是一个基础的结构体,用于描述所有对象的结构。它包含一个isa
指针,这个指针指向对象的类。 - 继承关系:
objc_object
并不是通过继承的概念来实现的,而是通过结构体嵌套来实现的。objc_object
是所有 Objective-C 对象的基础结构。
struct objc_object {
Class isa;
};
2. objc_class
继承自 objc_object
¶
- 准确性:
objc_class
是一个结构体,用于描述类的结构。它实际上是从objc_object
继承而来的,这意味着objc_class
也是一种特殊的objc_object
,因此它也包含一个isa
指针。
struct objc_class : objc_object {
Class super_class; // 指向父类
const char *name; // 类名
long version;
long info;
long instance_size;
struct objc_ivar_list *ivars; // 成员变量列表
struct objc_method_list **methodLists; // 方法列表
struct objc_cache *cache; // 方法缓存
struct objc_protocol_list *protocols; // 协议列表
};
3. isa
指针的作用¶
- 准确性:
isa
指针在objc_object
结构体中,用于连接对象、类和元类之间的关系。通过isa
指针,实例对象可以找到它的类对象,类对象可以找到它的元类对象。
4. 实例对象、类对象和元类对象的关系¶
- 实例对象:通过
alloc
和init
方法创建,每个实例对象的isa
指针指向它的类。 - 类对象:描述一类实例对象的结构和行为。类对象的
isa
指针指向它的元类。 - 元类对象:描述类对象的结构和行为。元类对象的
isa
指针通常指向根元类(如NSObject
的元类)。
示例结构¶
+----------------------+
| Root Metaclass |
+----------------------+
isa ^ |
| |
+-------+-------+
| Metaclass |
+----------------------+
isa ^ |
| |
+-------+-------+
| Class |
+----------------------+
isa ^ |
| |
+-------+-------+
| Instance Object |
+----------------------+
示例代码¶
以下代码展示了如何获取实例对象、类对象和元类对象,并打印它们的关系:
#import <objc/runtime.h>
#import <Foundation/Foundation.h>
@interface MyClass : NSObject
@end
@implementation MyClass
@end
int main(int argc, const char * argv[]) {
@autoreleasepool {
// 创建实例对象
MyClass *instance = [[MyClass alloc] init];
// 获取类对象
Class classObject = [MyClass class];
// 获取元类对象
Class metaclassObject = object_getClass(classObject);
// 获取根元类对象
Class rootMetaclassObject = object_getClass(metaclassObject);
// 打印结果
NSLog(@"Instance isa: %s", class_getName(object_getClass(instance)));
NSLog(@"Class name: %s", class_getName(classObject));
NSLog(@"Class isa (Metaclass): %s", class_getName(metaclassObject));
NSLog(@"Metaclass isa (Root Metaclass): %s", class_getName(rootMetaclassObject));
}
return 0;
}
进一步澄清¶
objc_object
:是所有对象的基础结构体,包括实例对象、类对象和元类对象。它通过isa
指针连接这些对象。objc_class
:是描述类的结构体,继承自objc_object
,因此它也是一个objc_object
。objc_class
中包含了描述类的其他信息,如方法列表、成员变量等。
总结¶
- 对象、类和元类:它们之间的关系是通过
isa
指针连接的。每个objc_object
都有一个isa
指针指向它的类,类对象的isa
指针指向它的元类,元类对象的isa
指针通常指向根元类。 isa
指针的位置:isa
指针位于objc_object
结构体中,是对象与类、类与元类之间的连接纽带。
你的理解基本是正确的,只是需要明确 objc_object
是基础结构体,而非传统意义上的基类。通过这种设计,Objective-C 能够实现其动态特性和灵活的消息传递机制。
objc_object 是 Objective-C 中所有对象的基类,实际上是一个包含 isa 指针的结构体。这个 isa 指针指向对象的类。
这是你之间说的,你觉得有没有歧义
你提到的句子确实可能引起一些歧义。特别是“基类”这个术语在上下文中的使用可能会让人误解。更准确地描述应该强调 objc_object
是一个基础结构体,而不是传统意义上的基类。我们可以这样改进:
原句¶
objc_object 是 Objective-C 中所有对象的基类,实际上是一个包含 isa 指针的结构体。这个 isa 指针指向对象的类。
改进后的描述¶
objc_object
是 Objective-C 中所有对象的基础结构体。它包含一个 isa
指针,该指针指向对象的类。
详细解释¶
- 基础结构体:
objc_object
是 Objective-C 运行时系统中描述所有对象的最基础的结构体。它并不是一个类,而是一个结构体定义。 isa
指针:isa
指针是objc_object
结构体中的一个成员,它指向对象所属的类。
整理后的总结¶
// 定义 `objc_object` 结构体
struct objc_object {
Class isa;
};
// 定义 `objc_class` 结构体,继承自 `objc_object`
struct objc_class : objc_object {
Class super_class; // 指向父类
const char *name; // 类名
long version;
long info;
long instance_size;
struct objc_ivar_list *ivars; // 成员变量列表
struct objc_method_list **methodLists; // 方法列表
struct objc_cache *cache; // 方法缓存
struct objc_protocol_list *protocols; // 协议列表
};
关键点¶
objc_object
:所有 Objective-C 对象的基础结构体,包含一个isa
指针。objc_class
:继承自objc_object
,描述类的结构体,包含类的详细信息(如方法列表、成员变量等)。isa
指针:用于将实例对象与其类对象、类对象与其元类对象连接起来。
结构图¶
+----------------------+
| Root Metaclass |
+----------------------+
isa ^ |
| |
+-------+-------+
| Metaclass |
+----------------------+
isa ^ |
| |
+-------+-------+
| Class |
+----------------------+
isa ^ |
| |
+-------+-------+
| Instance Object |
+----------------------+
示例代码¶
以下代码展示了如何获取实例对象、类对象和元类对象,并打印它们的关系:
#import <objc/runtime.h>
#import <Foundation/Foundation.h>
@interface MyClass : NSObject
@end
@implementation MyClass
@end
int main(int argc, const char * argv[]) {
@autoreleasepool {
// 创建实例对象
MyClass *instance = [[MyClass alloc] init];
// 获取类对象
Class classObject = [MyClass class];
// 获取元类对象
Class metaclassObject = object_getClass(classObject);
// 获取根元类对象
Class rootMetaclassObject = object_getClass(metaclassObject);
// 打印结果
NSLog(@"Instance isa: %s", class_getName(object_getClass(instance)));
NSLog(@"Class name: %s", class_getName(classObject));
NSLog(@"Class isa (Metaclass): %s", class_getName(metaclassObject));
NSLog(@"Metaclass isa (Root Metaclass): %s", class_getName(rootMetaclassObject));
}
return 0;
}
总结¶
objc_object
是所有 Objective-C 对象的基础结构体,而不是基类。- 该结构体包含一个
isa
指针,用于连接对象与类、类与元类之间的关系。 objc_class
是一个继承自objc_object
的结构体,描述类的详细信息。
这样改写可以避免歧义,更准确地描述 objc_object
和 objc_class
在 Objective-C 运行时系统中的角色。
cache_t, class_data_bits_t,class_rw_t,class_ro_t,method_t 给我解释一下这些都是干啥玩意的
在 Objective-C 的运行时(runtime)系统中,这些结构体和类型负责管理类和方法的信息。我们来详细解释一下 cache_t
、class_data_bits_t
、class_rw_t
、class_ro_t
和 method_t
这些类型的作用。
1. cache_t
¶
cache_t
是用于方法缓存的结构体。它在类的结构体中起到了加速方法查找的作用。当一个方法被调用时,runtime 系统首先会在这个缓存中查找,以减少方法查找的开销。
struct cache_t {
struct bucket_t *_buckets;
mask_t _mask;
mask_t _occupied;
};
_buckets
:缓存桶数组,存储方法的缓存条目。_mask
:用于计算索引的掩码。_occupied
:已使用的缓存条目的数量。
2. class_data_bits_t
¶
class_data_bits_t
是一个位域,包含类的只读和读写数据的指针。在 Apple 的运行时实现中,这个类型用于高效存储和访问类的数据。
typedef struct {
uintptr_t bits;
} class_data_bits_t;
bits
:存储类的数据指针,包括只读和读写数据。
3. class_rw_t
¶
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;
};
flags
:标志位,描述类的状态。version
:版本号。ro
:指向只读数据的指针。methods
:方法列表。properties
:属性列表。protocols
:协议列表。firstSubclass
:第一个子类。nextSiblingClass
:下一个兄弟类。demangledName
:解混淆后的类名。
4. class_ro_t
¶
class_ro_t
是类的只读数据的结构体,包含类的静态信息,如类名、实例大小、成员变量列表等。这些数据在运行时不可修改。
struct class_ro_t {
uint32_t flags;
uint32_t instanceStart;
uint32_t instanceSize;
const uint8_t * ivarLayout;
const char *name; // 类名
const method_list_t *baseMethods; // 基本方法列表
const protocol_list_t *baseProtocols; // 基本协议列表
const ivar_list_t *ivars; // 成员变量列表
const uint8_t *weakIvarLayout;
const property_list_t *properties; // 属性列表
};
flags
:标志位,描述类的状态。instanceStart
:实例变量起始位置。instanceSize
:实例大小。ivarLayout
:实例变量布局。name
:类名。baseMethods
:基本方法列表。baseProtocols
:基本协议列表。ivars
:成员变量列表。weakIvarLayout
:弱引用实例变量布局。properties
:属性列表。
5. method_t
¶
method_t
是表示方法的结构体,包含方法的相关信息。
struct method_t {
SEL name; // 方法选择器
const char *types; // 方法类型编码
IMP imp; // 方法实现的指针
};
name
:方法选择器(方法的名称)。types
:方法类型编码(描述方法参数和返回类型的编码)。imp
:方法实现的指针(指向方法的实现函数)。
结构和关系¶
这些结构体和类型在 Objective-C 的类和方法管理中起着关键作用。它们的关系和作用可以通过下面的示例代码来理解:
// 类对象结构示例
struct objc_class {
Class isa;
Class super_class;
cache_t cache; // 方法缓存
class_data_bits_t bits; // 类数据位域
};
// 类数据位域展开后的数据
struct class_data_t {
class_ro_t *ro; // 只读数据
class_rw_t *rw; // 读写数据
};
// 读写数据包含的方法列表
struct class_rw_t {
method_array_t methods; // 方法列表
// 其他字段省略
};
// 方法列表包含的方法
struct method_list_t {
uint32_t count;
method_t first;
};
总结¶
cache_t
:用于方法缓存,加速方法查找。class_data_bits_t
:包含类的只读和读写数据指针的位域。class_rw_t
:类的读写数据,包含方法列表、属性列表等,可以在运行时修改。class_ro_t
:类的只读数据,包含类名、实例大小、成员变量列表等,运行时不可修改。method_t
:表示方法的结构体,包含方法选择器、类型编码和实现指针。
这些结构体和类型共同构成了 Objective-C 运行时系统中的类和方法管理机制,使得类的定义、方法的查找和调用等操作得以高效执行。
isa_t 是啥 啥叫指针类型的 isa 和非指针类型的 isa
isa_t
是一个在 Objective-C 运行时中用来表示 isa
指针的结构体。它包含了指向对象的类的指针以及一些标志位,用于存储对象的附加信息。在现代的 Objective-C 运行时中,Apple 引入了“优化的 isa
”技术,这使得 isa
指针不仅仅是一个简单的指针,而是一个多用途的结构,包含多个字段。
指针类型的 isa
和非指针类型的 isa
¶
- 指针类型的
isa
:传统的isa
指针是一个简单的指针,直接指向对象的类。 - 非指针类型的
isa
:优化的isa
是一个包含多个字段的位域(bitfield),这些字段可以包含指向类的指针以及其他标志位和信息。
isa_t
结构体¶
在优化的 isa
实现中,isa
被定义为一个联合体,包含一个指针和一个位域。以下是 isa_t
的一个示例定义(简化版):
union isa_t {
Class cls;
uintptr_t bits;
};
struct obj {
isa_t isa;
};
优化的 isa
位域¶
在优化的 isa
实现中,isa_t
包含多个字段,例如:
- 类指针(class pointer):指向对象所属的类。
- 指针标志位(pointer bit):指示
isa
是否为指针类型。 - 弱引用计数(weak reference count):管理对象的弱引用计数。
- 额外标志位(extra flags):存储附加信息,如对象是否已被标记为自由等。
以下是一个更详细的示例:
union isa_t {
Class cls;
uintptr_t bits;
struct {
uintptr_t nonpointer : 1; // 指示是否为优化的 isa
uintptr_t has_assoc : 1; // 是否有关联对象
uintptr_t has_cxx_dtor : 1; // 是否有 C++ 析构函数
uintptr_t shiftcls : 33; // 类指针,偏移量
uintptr_t magic : 6; // 用于调试的魔术数
uintptr_t weakly_referenced : 1; // 是否有弱引用
uintptr_t deallocating : 1; // 是否正在析构
uintptr_t has_sidetable_rc : 1; // 是否有 side table 引用计数
uintptr_t extra_rc : 19; // 引用计数
};
};
指针类型的 isa
示例¶
// 指针类型的 isa
struct objc_object {
Class isa;
};
非指针类型的 isa
示例¶
// 非指针类型的 isa
struct objc_object {
union isa_t isa;
};
使用优化 isa
的好处¶
- 减少内存使用:通过在
isa
指针中存储额外的信息,可以减少对象中额外字段的数量。 - 提高性能:某些标志位和计数可以直接在
isa
中存储和访问,而无需额外的查找和操作。
例子:如何访问优化的 isa
¶
以下是如何访问和使用优化的 isa
的示例代码:
struct objc_object {
union isa_t isa;
};
// 获取类指针
Class get_class(struct objc_object *obj) {
if (obj->isa.nonpointer) {
return (Class)(obj->isa.shiftcls << 3);
} else {
return obj->isa.cls;
}
}
// 设置类指针
void set_class(struct objc_object *obj, Class cls) {
if (obj->isa.nonpointer) {
obj->isa.shiftcls = ((uintptr_t)cls) >> 3;
} else {
obj->isa.cls = cls;
}
}
总结¶
- 指针类型的
isa
是一个简单的指针,直接指向对象的类。 - 非指针类型的
isa
是一个包含多个字段的位域,用于存储类指针和附加信息。 - 优化
isa
提供了更高效的内存使用和性能,通过在isa
中存储额外的信息来减少对象的大小和提高操作的效率。
通过这种设计,Objective-C 运行时系统可以在保持高效方法调用和内存管理的同时,提供丰富的对象信息和功能。
我调用了一个类方法,但是没有实现,但是根类有个同名的实例方法,他会怎么调用
在 Objective-C 中,当你调用一个类方法(用 +
标记的方法),但是该方法没有在类中实现,而根类(如 NSObject
)中有一个同名的实例方法(用 -
标记的方法),系统不会自动调用根类的实例方法。类方法和实例方法是完全独立的,不能相互替代。
具体过程¶
- 方法查找:当你调用一个类方法时,运行时系统会在类的方法列表中查找该方法。
- 查找失败:如果在该类中没有找到该类方法,运行时系统会沿着类的继承链向上查找,直到根类(如
NSObject
)。 - 最终失败:如果在根类中也没有找到该类方法,运行时系统不会去查找同名的实例方法,而是认为该方法不存在。
处理方法未实现的情况¶
当一个类方法未实现时,运行时系统会转向消息转发机制。下面是消息转发过程的简要介绍:
1. 动态方法解析¶
首先,运行时系统会调用类方法 +resolveClassMethod:
,让你有机会动态添加方法实现。
+ (BOOL)resolveClassMethod:(SEL)sel {
if (sel == @selector(myClassMethod)) {
// 动态添加方法实现
class_addMethod(object_getClass(self), sel, (IMP)myClassMethodIMP, "v@:");
return YES;
}
return [super resolveClassMethod:sel];
}
2. 快速转发¶
如果动态方法解析没有添加方法实现,运行时系统会调用 -forwardingTargetForSelector:
方法,让你返回一个可以响应该方法的对象。
+ (id)forwardingTargetForSelector:(SEL)aSelector {
if (aSelector == @selector(myClassMethod)) {
return [AnotherClass class];
}
return [super forwardingTargetForSelector:aSelector];
}
3. 常规转发¶
如果快速转发也未处理,运行时系统会调用 -methodSignatureForSelector:
获取方法签名,并调用 -forwardInvocation:
进行消息转发。
+ (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector {
if (aSelector == @selector(myClassMethod)) {
return [NSMethodSignature signatureWithObjCTypes:"v@:"];
}
return [super methodSignatureForSelector:aSelector];
}
+ (void)forwardInvocation:(NSInvocation *)anInvocation {
SEL sel = [anInvocation selector];
if (sel == @selector(myClassMethod)) {
// 处理未实现的方法
} else {
[super forwardInvocation:anInvocation];
}
}
总结¶
- 类方法和实例方法是独立的:它们不能互相替代,即使名称相同。
- 消息转发机制:当一个类方法未实现时,运行时系统会通过动态方法解析、快速转发和常规转发来处理未实现的方法,而不会去调用同名的实例方法。
因此,如果你调用一个未实现的类方法,即使根类中有一个同名的实例方法,运行时系统也不会调用该实例方法。你需要通过消息转发机制来处理未实现的类方法。
如果我调用一个类的类方法,但是没有这个方法,有一个同名的实例方法,此时会不会崩溃
如果你调用一个类方法,但是该类没有实现这个方法,同时根类有一个同名的实例方法,程序确实会崩溃。具体来说,当你调用一个类方法时,运行时系统会按照以下步骤查找和处理该方法:
- 查找类方法:首先,运行时系统会在类的方法列表中查找该类方法。
- 查找父类方法:如果在当前类中没有找到该类方法,系统会沿着继承链向上查找,直到根类(通常是
NSObject
)。 - 消息转发机制:如果在继承链中也没有找到该类方法,运行时系统会进入消息转发机制。
在消息转发机制中,如果没有适当处理,最终会导致崩溃。具体来说,以下是消息转发的详细步骤:
消息转发机制¶
1. 动态方法解析¶
首先,运行时系统会调用 +resolveClassMethod:
方法,尝试动态添加该类方法。如果没有添加该方法,继续下一步。
+ (BOOL)resolveClassMethod:(SEL)sel {
// 可以在这里动态添加类方法
return [super resolveClassMethod:sel];
}
2. 快速转发¶
如果动态方法解析没有添加方法实现,运行时系统会调用 +forwardingTargetForSelector:
方法,尝试找到一个可以响应该消息的对象。
+ (id)forwardingTargetForSelector:(SEL)aSelector {
// 可以在这里返回一个可以响应该消息的对象
return [super forwardingTargetForSelector:aSelector];
}
3. 常规转发¶
如果快速转发也没有处理,运行时系统会调用 +methodSignatureForSelector:
获取方法签名,如果返回 nil
,则会直接崩溃。
+ (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector {
// 获取方法签名
NSMethodSignature *signature = [super methodSignatureForSelector:aSelector];
return signature;
}
+ (void)forwardInvocation:(NSInvocation *)anInvocation {
// 处理未实现的方法
[super forwardInvocation:anInvocation];
}
具体示例¶
#import <Foundation/Foundation.h>
@interface MyClass : NSObject
- (void)instanceMethod;
@end
@implementation MyClass
- (void)instanceMethod {
NSLog(@"Instance method called");
}
@end
int main(int argc, const char * argv[]) {
@autoreleasepool {
[MyClass performSelector:@selector(instanceMethod)];
}
return 0;
}
在上面的示例中,MyClass
类没有实现 +instanceMethod
类方法,而只有 -instanceMethod
实例方法。如果直接调用 [MyClass instanceMethod]
,运行时系统会按照上述步骤查找类方法,最后会因为找不到类方法并且未正确处理消息转发而崩溃。
崩溃示例¶
崩溃时会产生类似如下的错误信息:
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '+[MyClass instanceMethod]: unrecognized selector sent to class 0x10050c0a8'
防止崩溃的方法¶
要防止这种崩溃,你可以通过实现消息转发机制来处理未实现的类方法。例如:
@implementation MyClass
+ (BOOL)resolveClassMethod:(SEL)sel {
if (sel == @selector(instanceMethod)) {
// 动态添加类方法实现
class_addMethod(object_getClass(self), sel, (IMP)dynamicClassMethod, "v@:");
return YES;
}
return [super resolveClassMethod:sel];
}
void dynamicClassMethod(id self, SEL _cmd) {
NSLog(@"Dynamic class method called");
}
@end
这样,如果调用未实现的 +instanceMethod
类方法,运行时系统会动态添加该方法并避免崩溃。
总结¶
- 类方法和实例方法是独立的:调用一个类方法时,系统不会查找同名的实例方法。
- 未实现的类方法会导致崩溃:如果没有处理消息转发机制,调用未实现的类方法会导致程序崩溃。
- 消息转发机制可以处理未实现的方法:通过实现
+resolveClassMethod:
、+forwardingTargetForSelector:
和+methodSignatureForSelector:
等方法,可以处理未实现的类方法,避免崩溃。
根元类对象的 superclass 指向谁
在 Objective-C 的类层次结构中,根元类(root metaclass)对象的 superclass
指针有一个特定的指向,以保持类结构的完整性和一致性。下面是详细解释:
类和元类的层次结构¶
- 实例对象:每个实例对象的
isa
指针指向其对应的类对象。 - 类对象:每个类对象的
isa
指针指向其对应的元类对象。 - 元类对象:每个元类对象的
isa
指针指向其超类的元类对象。最终,根元类对象的isa
指针指向自身。
superclass
指针的指向¶
- 普通类的
superclass
:普通类的superclass
指针指向其父类。 - 元类的
superclass
:元类的superclass
指针指向其父类的元类。
根元类的 superclass
指向¶
在 Objective-C 中,根类通常是 NSObject
或 NSProxy
。以 NSObject
为例:
NSObject
类对象:其superclass
为nil
。NSObject
元类对象:其superclass
为NSObject
类对象。
这意味着根元类的 superclass
指针指向根类对象本身。
层次结构图示¶
NSObject
类对象isa
->NSObject
元类对象superclass
->nil
NSObject
元类对象isa
->NSObject
元类对象(指向自身)superclass
->NSObject
类对象
例子¶
为了更清晰地理解这个结构,以下是一个示例代码片段:
// NSObject 类对象
Class nsObjectClass = [NSObject class];
// NSObject 元类对象
Class nsObjectMetaClass = object_getClass(nsObjectClass);
// 根类对象的 superclass 为 nil
NSLog(@"NSObject superclass: %@", class_getSuperclass(nsObjectClass)); // 输出: nil
// 元类对象的 superclass 指向根类对象
NSLog(@"NSObject metaclass superclass: %@", class_getSuperclass(nsObjectMetaClass)); // 输出: NSObject
总结¶
- 根元类对象的
superclass
指针指向根类对象。 - 根类对象的
superclass
为nil
。 - 元类对象的
superclass
指向其父类的元类对象。
这种设计保证了类和元类层次结构的闭环,保持了结构的一致性和完整性。
当调用一个类方法时,如果该类方法没有实现,则会调用同名的实例方法。这样说我有点不理解,应该是只针对NSObject类吧,其他类没有这个特性吧。
你的理解有误。在 Objective-C 中,类方法和实例方法是完全独立的,无论是 NSObject
类还是其他类,它们都没有这个特性,即类方法未实现时不会自动调用同名的实例方法。
详细解释¶
- 类方法和实例方法的独立性:类方法(标记为
+
)和实例方法(标记为-
)是不同的。它们在方法查找、调用和消息转发过程中是分开处理的。调用一个类方法时,系统只会在类方法列表中查找,不会查找实例方法列表。
运行时行为¶
- 方法查找:当你调用一个类方法时,运行时系统首先在类方法列表中查找该方法。
- 继承链查找:如果在当前类中没有找到,系统会沿着继承链向上查找,直到根类(通常是
NSObject
或NSProxy
)。 - 消息转发:如果在整个继承链中都没有找到该方法实现,系统会进入消息转发机制。
消息转发机制¶
在消息转发机制中,如果没有处理,最终会导致崩溃。具体来说,以下是消息转发的详细步骤:
动态方法解析¶
运行时系统会首先调用 +resolveClassMethod:
方法,让你有机会动态添加该类方法的实现。
+ (BOOL)resolveClassMethod:(SEL)sel {
if (sel == @selector(myClassMethod)) {
// 动态添加类方法实现
class_addMethod(object_getClass(self), sel, (IMP)myClassMethodIMP, "v@:");
return YES;
}
return [super resolveClassMethod:sel];
}
快速转发¶
如果动态方法解析没有添加方法实现,运行时系统会调用 +forwardingTargetForSelector:
方法,让你返回一个可以响应该消息的对象。
+ (id)forwardingTargetForSelector:(SEL)aSelector {
if (aSelector == @selector(myClassMethod)) {
return [AnotherClass class];
}
return [super forwardingTargetForSelector:aSelector];
}
常规转发¶
如果快速转发也没有处理,运行时系统会调用 +methodSignatureForSelector:
获取方法签名,如果返回 nil
,则会直接崩溃。
+ (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector {
if (aSelector == @selector(myClassMethod)) {
return [NSMethodSignature signatureWithObjCTypes:"v@:"];
}
return [super methodSignatureForSelector:aSelector];
}
+ (void)forwardInvocation:(NSInvocation *)anInvocation {
SEL sel = [anInvocation selector];
if (sel == @selector(myClassMethod)) {
// 处理未实现的方法
} else {
[super forwardInvocation:anInvocation];
}
}
示例¶
@interface MyClass : NSObject
- (void)myInstanceMethod;
@end
@implementation MyClass
- (void)myInstanceMethod {
NSLog(@"Instance method called");
}
@end
int main(int argc, const char * argv[]) {
@autoreleasepool {
// 这是调用类方法
[MyClass myInstanceMethod];
}
return 0;
}
在上面的示例中,MyClass
类没有实现 +myInstanceMethod
类方法,只有 -myInstanceMethod
实例方法。如果直接调用 [MyClass myInstanceMethod]
,程序会崩溃,因为系统不会自动调用同名的实例方法。
总结¶
- 类方法和实例方法是独立的:调用类方法时,系统不会查找同名的实例方法。
- NSObject 类没有特殊处理:
NSObject
类以及所有其他类都是如此,类方法和实例方法的查找、调用和消息转发机制是统一的,不存在特殊处理。 - 消息转发机制:通过实现
+resolveClassMethod:
、+forwardingTargetForSelector:
和+methodSignatureForSelector:
等方法,可以处理未实现的类方法,避免崩溃,但不会涉及实例方法的调用。
因此,类方法未实现时不会调用同名的实例方法,不论是 NSObject
类还是其他类,情况都是如此。
import "Mobile.h"¶
@interface Phone : Mobile @end @implementation Phone - (id)init { self = [super init];
if (self) { NSLog(@"%0", NSStringFromClass([self class])); NSLog(@"%@", NSStringFromClass ([super flass])); } return self; }
你在代码示例中遇到了一些问题,我将帮助你纠正这些问题,并解释一些关键点。
修正后的代码示例¶
- 确保类定义和导入头文件正确。
- 修正方法
NSStringFromClass
的调用,确保输出正确。 - 修正花括号和其他语法错误。
#import "Mobile.h"
@interface Phone : Mobile
@end
@implementation Phone
- (id)init {
self = [super init];
if (self) {
NSLog(@"%@", NSStringFromClass([self class]));
NSLog(@"%@", NSStringFromClass([super class]));
}
return self;
}
@end
解释¶
self
和 super
¶
self
是指当前实例对象。super
是指向当前实例的父类部分,调用super
时会告诉编译器去父类的方法中查找实现。
[self class]
和 [super class]
¶
[self class]
调用会返回当前实例的类名。[super class]
实际上也是返回当前实例的类名,因为super
并不改变self
指向的对象,只是改变了方法查找路径。
因此,无论是 [self class]
还是 [super class]
,都会返回当前实例的类名。在你的代码中,NSLog(@"%@", NSStringFromClass([self class]));
和 NSLog(@"%@", NSStringFromClass([super class]));
都会打印 Phone
。
代码执行结果¶
在你的 Phone
类的 init
方法中,如果创建一个 Phone
的实例:
Phone *phone = [[Phone alloc] init];
输出结果将是:
Phone
Phone
这表明无论是 [self class]
还是 [super class]
,都返回了当前实例的类名 Phone
。
注意事项¶
- 确保
Mobile
类已经正确定义并包含在项目中。 - 注意 Objective-C 的语法和代码格式。
希望这能帮助你理解 self
和 super
的用法以及 [self class]
和 [super class]
的区别。如有进一步问题,请随时提问。
没懂,继续深一步给我解释,self class 是不是 等于 [Phone class], 这是一个类对象?这个 class 方法是不是 会到根元类中查找 也就是 nsobject 的 元类。找到了就调用 返回的是啥呢。 super class 是不是相当于 Moble class],也是最终到 nsobject 中的根元类中查找?那返回的是啥呢。
self class
和 super class
的解释¶
self class
¶
[self class]
调用的是当前实例的 class
方法。这意味着它会返回当前对象所属的类。
- 实例对象:当你在一个实例方法中调用
[self class]
时,它会返回当前实例对象的类,即实例对象的isa
指针所指向的类。 - 类对象:如果你调用
[Phone class]
,这将返回Phone
类对象。
super class
¶
[super class]
也是调用当前实例的 class
方法,但用 super
的语法提示编译器从父类中查找方法实现。不过,class
方法是继承自 NSObject
的,所以无论是通过 self
还是 super
调用,它们最终调用的是 NSObject
的 class
方法。
深入理解类对象和元类¶
- 类对象:
[Phone class]
返回Phone
类对象。 - 元类对象:每个类对象的
isa
指针指向其对应的元类对象。
class
方法的查找过程¶
[self class]
和[super class]
最终都会调用NSObject
的class
方法。class
方法会返回调用者的类,即当前对象的isa
指针所指向的类。
代码示例和执行流程¶
#import "Mobile.h"
@interface Phone : Mobile
@end
@implementation Phone
- (id)init {
self = [super init];
if (self) {
NSLog(@"%@", NSStringFromClass([self class])); // Line A
NSLog(@"%@", NSStringFromClass([super class])); // Line B
}
return self;
}
@end
- Line A:
NSStringFromClass([self class])
调用时,[self class]
返回当前实例的类,即Phone
。 - Line B:
NSStringFromClass([super class])
调用时,虽然语法使用super
,但依旧返回当前实例的类,即Phone
。
实际执行过程¶
-
创建实例:
objective-c Phone *phone = [[Phone alloc] init];
-
[self class]
调用:- 调用
Phone
实例的class
方法。 - 通过
isa
指针查找到Phone
类对象。 - 返回
Phone
类对象。
- 调用
-
[super class]
调用:- 调用
Phone
实例的class
方法。 super
语法会查找父类的class
方法,但返回值仍然是当前对象的类。- 结果与
[self class]
相同,返回Phone
类对象。
- 调用
总结¶
[self class]
返回的是当前实例的类,即Phone
。[super class]
实际上也是返回当前实例的类,即Phone
,因为super
只是改变了方法查找路径,并没有改变实际调用者的isa
指针。
不论使用 [self class]
还是 [super class]
,最终都返回当前实例的类名,因为 class
方法定义在 NSObject
中,而所有类最终都继承自 NSObject
。 class
方法返回的就是调用者的 isa
指针指向的类。
这样一来,无论是通过 self
还是 super
调用 class
方法,都返回当前对象所属的类。
动态添加方法
在 Objective-C 中,动态添加方法是一种强大的功能,允许你在运行时向类中添加方法。这通常在以下几种情况下非常有用:
- 动态扩展类的功能。
- 在运行时处理未知选择器。
- 实现消息转发机制。
动态添加方法的步骤¶
- 定义方法的实现:实现一个 C 函数,作为动态添加方法的实现。
- 动态添加方法:使用
class_addMethod
函数将该实现添加到类中。 - 处理未实现的方法:通过
resolveInstanceMethod
或resolveClassMethod
方法来处理未实现的方法。
代码示例¶
以下是一个完整的示例,展示了如何动态添加一个实例方法和类方法。
定义类和方法实现¶
首先,定义一个类 MyClass
和一个动态添加的方法实现。
#import <objc/runtime.h>
#import <Foundation/Foundation.h>
@interface MyClass : NSObject
@end
@implementation MyClass
@end
// 动态添加的方法实现
void dynamicMethodIMP(id self, SEL _cmd) {
NSLog(@"Dynamic method -dynamicMethod called");
}
动态添加实例方法¶
在类的实现中,重写 +resolveInstanceMethod:
方法,以动态添加方法。
@implementation MyClass
+ (BOOL)resolveInstanceMethod:(SEL)sel {
if (sel == @selector(dynamicMethod)) {
class_addMethod([self class], sel, (IMP)dynamicMethodIMP, "v@:");
return YES;
}
return [super resolveInstanceMethod:sel];
}
@end
动态添加类方法¶
类似地,重写 +resolveClassMethod:
方法,以动态添加类方法。
@implementation MyClass (DynamicClassMethod)
+ (BOOL)resolveClassMethod:(SEL)sel {
if (sel == @selector(dynamicClassMethod)) {
Class metaClass = objc_getMetaClass(class_getName([self class]));
class_addMethod(metaClass, sel, (IMP)dynamicMethodIMP, "v@:");
return YES;
}
return [super resolveClassMethod:sel];
}
@end
使用动态添加的方法¶
最后,在主函数中调用这些方法。
int main(int argc, const char * argv[]) {
@autoreleasepool {
MyClass *myObject = [[MyClass alloc] init];
// 调用动态添加的实例方法
if ([myObject respondsToSelector:@selector(dynamicMethod)]) {
[myObject performSelector:@selector(dynamicMethod)];
}
// 调用动态添加的类方法
if ([MyClass respondsToSelector:@selector(dynamicClassMethod)]) {
[MyClass performSelector:@selector(dynamicClassMethod)];
}
}
return 0;
}
代码解释¶
-
动态添加实例方法:
+resolveInstanceMethod:
方法在实例方法查找失败时被调用。- 如果方法选择器是
@selector(dynamicMethod)
,则使用class_addMethod
动态添加该方法。 class_addMethod
的参数包括类、选择器、方法实现和类型编码。IMP
类型是指向方法实现的指针。"v@:"
是类型编码,表示返回类型为void
,参数为self
和_cmd
。
-
动态添加类方法:
+resolveClassMethod:
方法在类方法查找失败时被调用。- 使用
objc_getMetaClass
获取元类,然后使用class_addMethod
向元类添加方法。 - 元类的类型编码与实例方法相同。
运行结果¶
当运行上述代码时,会看到如下输出:
Dynamic method -dynamicMethod called
Dynamic method -dynamicMethod called
这表明动态添加的实例方法和类方法都被成功调用。
总结¶
- 动态方法解析:通过重写
+resolveInstanceMethod:
和+resolveClassMethod:
方法,可以在运行时动态添加方法。 - 方法添加:使用
class_addMethod
将方法添加到类或元类中。 - 方法实现:动态添加的方法实现可以是一个 C 函数,指向
IMP
类型。
这种技术在许多高级场景中非常有用,例如为现有类添加功能、处理未知消息、实现消息转发等。
我有个问题,就是我调用的这个方法,我怎么先判断一下 这个方法是否存在,如果不存在 我在动态添加啊
在 Objective-C 中,可以使用 respondsToSelector:
方法来检查某个对象是否能够响应特定的选择器(即方法)。对于类方法,可以使用 instancesRespondToSelector:
方法来检查类是否能够响应特定的实例方法选择器。通过这些方法,可以在调用方法之前检查其存在性,如果不存在,则动态添加该方法。
判断方法是否存在并动态添加方法¶
以下是一个示例,展示如何在调用方法之前检查其存在性,如果方法不存在则动态添加该方法。
定义类和方法实现¶
#import <objc/runtime.h>
#import <Foundation/Foundation.h>
@interface MyClass : NSObject
@end
@implementation MyClass
@end
// 动态添加的方法实现
void dynamicMethodIMP(id self, SEL _cmd) {
NSLog(@"Dynamic method -dynamicMethod called");
}
动态添加实例方法的代码¶
在类的实现中,重写 +resolveInstanceMethod:
方法,并添加一个检查方法存在性的函数。
@implementation MyClass
+ (BOOL)resolveInstanceMethod:(SEL)sel {
if (sel == @selector(dynamicMethod)) {
class_addMethod([self class], sel, (IMP)dynamicMethodIMP, "v@:");
return YES;
}
return [super resolveInstanceMethod:sel];
}
// 检查并动态添加方法
+ (void)checkAndAddMethod:(SEL)sel {
if (![self instancesRespondToSelector:sel]) {
[self resolveInstanceMethod:sel];
}
}
@end
动态添加类方法的代码¶
类似地,为类方法添加检查和动态添加代码。
@implementation MyClass (DynamicClassMethod)
+ (BOOL)resolveClassMethod:(SEL)sel {
if (sel == @selector(dynamicClassMethod)) {
Class metaClass = objc_getMetaClass(class_getName([self class]));
class_addMethod(metaClass, sel, (IMP)dynamicMethodIMP, "v@:");
return YES;
}
return [super resolveClassMethod:sel];
}
// 检查并动态添加类方法
+ (void)checkAndAddClassMethod:(SEL)sel {
if (![self respondsToSelector:sel]) {
[self resolveClassMethod:sel];
}
}
@end
使用动态添加的方法¶
在主函数中,先检查方法是否存在,如果不存在则动态添加方法,然后调用该方法。
int main(int argc, const char * argv[]) {
@autoreleasepool {
MyClass *myObject = [[MyClass alloc] init];
// 检查并添加实例方法
[MyClass checkAndAddMethod:@selector(dynamicMethod)];
if ([myObject respondsToSelector:@selector(dynamicMethod)]) {
[myObject performSelector:@selector(dynamicMethod)];
}
// 检查并添加类方法
[MyClass checkAndAddClassMethod:@selector(dynamicClassMethod)];
if ([MyClass respondsToSelector:@selector(dynamicClassMethod)]) {
[MyClass performSelector:@selector(dynamicClassMethod)];
}
}
return 0;
}
解释¶
- 判断实例方法是否存在:
+ (void)checkAndAddMethod:(SEL)sel
方法使用instancesRespondToSelector:
来检查实例方法是否存在。-
如果不存在,则调用
resolveInstanceMethod:
动态添加方法。 -
判断类方法是否存在:
+ (void)checkAndAddClassMethod:(SEL)sel
方法使用respondsToSelector:
来检查类方法是否存在。-
如果不存在,则调用
resolveClassMethod:
动态添加方法。 -
调用方法:
- 在检查并动态添加方法后,使用
performSelector:
来调用方法。
运行结果¶
当运行上述代码时,如果 dynamicMethod
和 dynamicClassMethod
方法不存在,它们将被动态添加,然后成功调用:
Dynamic method -dynamicMethod called
Dynamic method -dynamicMethod called
总结¶
通过使用 respondsToSelector:
和 instancesRespondToSelector:
方法,可以在运行时检查方法的存在性,并在必要时动态添加方法。这种机制可以在调用方法之前确保方法的存在,从而提高代码的灵活性和健壮性。
注册类
在 Objective-C 中,动态注册类是一种高级功能,可以在运行时创建新的类。这种功能主要通过运行时库函数来实现,特别是 objc_allocateClassPair
和 objc_registerClassPair
函数。
注册类的步骤¶
- 分配类对(Allocate Class Pair):使用
objc_allocateClassPair
创建一个新的类和它的元类。 - 添加成员变量和方法:向新类中添加实例变量和方法。
- 注册类对(Register Class Pair):使用
objc_registerClassPair
注册类和元类,使其可以在程序中使用。
代码示例¶
以下是一个完整的示例,展示了如何动态注册一个新的类,并向其添加方法和实例变量。
导入运行时库¶
#import <objc/runtime.h>
#import <Foundation/Foundation.h>
动态方法实现¶
定义一个动态添加的方法实现:
void dynamicMethodIMP(id self, SEL _cmd) {
NSLog(@"Dynamic method -dynamicMethod called");
}
注册类¶
实现动态注册类的代码:
int main(int argc, const char * argv[]) {
@autoreleasepool {
// 动态创建一个新类 MyDynamicClass,它继承自 NSObject
Class MyDynamicClass = objc_allocateClassPair([NSObject class], "MyDynamicClass", 0);
// 添加实例变量
class_addIvar(MyDynamicClass, "dynamicVariable", sizeof(NSString *), log2(sizeof(NSString *)), "@");
// 添加实例方法
BOOL methodAdded = class_addMethod(MyDynamicClass, @selector(dynamicMethod), (IMP)dynamicMethodIMP, "v@:");
if (methodAdded) {
NSLog(@"Method -dynamicMethod added successfully");
} else {
NSLog(@"Failed to add method -dynamicMethod");
}
// 注册类
objc_registerClassPair(MyDynamicClass);
// 创建动态类的实例
id dynamicInstance = [[MyDynamicClass alloc] init];
// 设置实例变量
NSString *dynamicValue = @"Hello, Dynamic World!";
[dynamicInstance setValue:dynamicValue forKey:@"dynamicVariable"];
// 获取实例变量
NSString *retrievedValue = [dynamicInstance valueForKey:@"dynamicVariable"];
NSLog(@"Retrieved value from dynamicVariable: %@", retrievedValue);
// 调用动态添加的方法
if ([dynamicInstance respondsToSelector:@selector(dynamicMethod)]) {
[dynamicInstance performSelector:@selector(dynamicMethod)];
}
}
return 0;
}
代码解释¶
- 分配类对:
objc_allocateClassPair
函数用于创建一个新的类和它的元类。这个函数需要三个参数:父类、类名和额外的内存大小(通常为0)。-
在这个示例中,
MyDynamicClass
继承自NSObject
。 -
添加成员变量:
class_addIvar
函数用于向类添加实例变量。-
参数包括类、变量名、变量大小、对齐方式和编码类型。
-
添加实例方法:
class_addMethod
函数用于向类添加实例方法。- 参数包括类、选择器、方法实现(
IMP
)和类型编码。 -
在这个示例中,添加了一个名为
dynamicMethod
的方法。 -
注册类对:
-
objc_registerClassPair
函数用于注册类和元类,使其可以在程序中使用。 -
使用动态类:
- 创建动态类的实例:
[[MyDynamicClass alloc] init]
。 - 设置和获取实例变量:使用
setValue:forKey:
和valueForKey:
。 - 调用动态添加的方法:使用
performSelector:
。
运行结果¶
当运行上述代码时,会看到如下输出:
Method -dynamicMethod added successfully
Retrieved value from dynamicVariable: Hello, Dynamic World!
Dynamic method -dynamicMethod called
这表明动态类的实例变量和方法都被成功设置和调用。
总结¶
- 动态注册类:通过
objc_allocateClassPair
和objc_registerClassPair
函数,可以在运行时创建和注册新的类。 - 添加成员变量和方法:使用
class_addIvar
和class_addMethod
函数,可以向新类添加实例变量和方法。 - 灵活性和动态性:这种机制提供了极大的灵活性,允许你在运行时扩展类的功能,实现动态行为。
runtime 动态添加方法 和 performselector 啥关系
在 Objective-C 中,runtime 动态添加方法与 performSelector
方法有密切关系。动态添加方法允许你在运行时向类或实例添加方法,而 performSelector
方法则用于在运行时调用一个选择器对应的方法。理解它们的关系和交互可以帮助你更好地利用 Objective-C 的动态特性。
动态添加方法¶
通过 runtime 机制,你可以在运行时向类或实例动态添加方法。这在某些场景下非常有用,例如扩展现有类的功能,或者处理未知选择器。
示例:动态添加方法¶
#import <objc/runtime.h>
#import <Foundation/Foundation.h>
// 动态添加的方法实现
void dynamicMethodIMP(id self, SEL _cmd) {
NSLog(@"Dynamic method -dynamicMethod called");
}
@interface MyClass : NSObject
@end
@implementation MyClass
@end
动态添加方法的代码¶
在类的实现中,通过重写 +resolveInstanceMethod:
方法来动态添加方法。
@implementation MyClass
+ (BOOL)resolveInstanceMethod:(SEL)sel {
if (sel == @selector(dynamicMethod)) {
class_addMethod([self class], sel, (IMP)dynamicMethodIMP, "v@:");
return YES;
}
return [super resolveInstanceMethod:sel];
}
@end
使用 performSelector
调用方法¶
performSelector
方法允许你在运行时调用一个选择器对应的方法。这对于调用在编译时并不确定的方法非常有用,尤其是在你动态添加方法的场景中。
示例:使用 performSelector
调用动态添加的方法¶
int main(int argc, const char * argv[]) {
@autoreleasepool {
MyClass *myObject = [[MyClass alloc] init];
// 尝试调用 dynamicMethod 方法
if ([myObject respondsToSelector:@selector(dynamicMethod)]) {
[myObject performSelector:@selector(dynamicMethod)];
}
}
return 0;
}
解释 performSelector
和动态添加方法的关系¶
-
方法查找和动态添加:
- 当你调用
performSelector:
时,系统会首先在当前对象的方法列表中查找对应的选择器。 - 如果没有找到对应的方法实现,系统会调用
+resolveInstanceMethod:
方法(对于类方法,调用+resolveClassMethod:
)。 - 在
+resolveInstanceMethod:
方法中,你可以动态添加该选择器对应的方法实现。
- 当你调用
-
动态添加后的调用:
- 一旦方法被动态添加,再次调用
performSelector:
时,就能够找到并调用刚刚添加的方法。
- 一旦方法被动态添加,再次调用
总结¶
- 动态添加方法:通过 runtime 机制,可以在运行时向类或实例动态添加方法。这通常在
+resolveInstanceMethod:
或+resolveClassMethod:
方法中实现。 - performSelector 调用:
performSelector:
方法用于在运行时调用一个选择器对应的方法。它依赖于方法查找机制,因此如果在首次调用时没有找到方法,可以通过resolveInstanceMethod:
动态添加该方法。 - 关系:在首次调用
performSelector:
时,如果方法不存在,可以通过resolveInstanceMethod:
动态添加该方法,之后再次调用performSelector:
时,方法已经存在,可以直接调用。
通过这种机制,Objective-C 提供了高度的灵活性和动态性,使得程序可以在运行时根据需要添加或调用方法,从而实现更复杂和动态的行为。
动态添加的方法 能通过 【obj xxx] 这样调用么,还是只能使用 performselector 调用
在 Objective-C 中,动态添加的方法可以通过 [obj methodName]
这种常规方法调用方式使用,也可以通过 performSelector
调用。两者没有区别,都是通过 Objective-C 的方法调用机制来执行的。
通过常规方式调用动态添加的方法¶
以下是一个完整的示例,展示如何动态添加方法并通过常规方法调用它。
定义类和方法实现¶
首先,定义一个类 MyClass
和一个动态添加的方法实现:
#import <objc/runtime.h>
#import <Foundation/Foundation.h>
@interface MyClass : NSObject
@end
@implementation MyClass
@end
// 动态添加的方法实现
void dynamicMethodIMP(id self, SEL _cmd) {
NSLog(@"Dynamic method -dynamicMethod called");
}
动态添加实例方法¶
在类的实现中,重写 +resolveInstanceMethod:
方法,以动态添加方法:
@implementation MyClass
+ (BOOL)resolveInstanceMethod:(SEL)sel {
if (sel == @selector(dynamicMethod)) {
class_addMethod([self class], sel, (IMP)dynamicMethodIMP, "v@:");
return YES;
}
return [super resolveInstanceMethod:sel];
}
@end
使用动态添加的方法¶
在主函数中,通过常规方法调用和 performSelector
调用动态添加的方法:
int main(int argc, const char * argv[]) {
@autoreleasepool {
MyClass *myObject = [[MyClass alloc] init];
// 使用常规方式调用动态添加的方法
if ([myObject respondsToSelector:@selector(dynamicMethod)]) {
[myObject dynamicMethod];
}
// 使用 performSelector 调用动态添加的方法
if ([myObject respondsToSelector:@selector(dynamicMethod)]) {
[myObject performSelector:@selector(dynamicMethod)];
}
}
return 0;
}
代码解释¶
-
动态添加实例方法:
- 在
+resolveInstanceMethod:
方法中,检查选择器是否为@selector(dynamicMethod)
。 - 如果是,则使用
class_addMethod
函数将dynamicMethodIMP
方法实现添加到MyClass
类中。 - 返回
YES
表示方法添加成功。
- 在
-
使用常规方式调用方法:
- 检查对象是否响应
dynamicMethod
方法(即该方法是否存在)。 - 如果存在,直接通过
[myObject dynamicMethod]
调用方法。
- 检查对象是否响应
-
使用
performSelector
调用方法:- 同样的检查对象是否响应
dynamicMethod
方法。 - 如果存在,通过
[myObject performSelector:@selector(dynamicMethod)]
调用方法。
- 同样的检查对象是否响应
总结¶
- 常规方法调用:可以直接通过
[obj methodName]
调用动态添加的方法,只要在调用之前确保该方法已经添加。 performSelector
调用:可以通过performSelector
调用动态添加的方法,同样需要确保方法已经添加。- 方法查找机制:无论是通过常规方式还是
performSelector
调用,Objective-C 的方法查找机制都会确保在调用方法之前执行+resolveInstanceMethod:
或+resolveClassMethod:
来动态添加方法。
通过这种机制,Objective-C 提供了灵活的动态方法处理能力,使得程序可以在运行时根据需要添加或调用方法,从而实现更复杂和动态的行为。