IMP定义在runtime的objc.h中,定义如下:
/// A pointer to the function of a method implementation.
#if !OBJC_OLD_DISPATCH_PROTOTYPES
typedef void (*IMP)(void /* id, SEL, ... */ );
#else
typedef id _Nullable (*IMP)(id _Nonnull, SEL _Nonnull, ...);
#endif
typedef说明
形式:typedef 返回类型(新类型)(参数表)
typedef void (IMP)(void / id, SEL, ... */ ); // 定义一个名为IMP的函数指针
IMP是指向方法实现的函数指针,第一个参数是指向self的指针,第二个参数是方法选择器(SEL)。
IMP、SEL、Method
Method声明在objc-private.h中
typedef struct method_t *Method;
Method定义在objc-runtime.h文件中,定义如下:
struct method_t {
SEL name;
const char *types;
IMP imp;
struct SortBySELAddress :
public std::binary_function<const method_t&,
const method_t&, bool>
{
bool operator() (const method_t& lhs,
const method_t& rhs)
{ return lhs.name < rhs.name; }
};
};
Method是方法的结构体,SEL和IMP是Method的成员变量,SEL表示方法选择器(@selector)的隐含类型,IMP是指向方法的实现的指针。
方法选择器用于表示方法运行时的名称。方法选择器是个C字符串,在运行时注册(或 “mapped”)。当类加载时(load),编译器生成的方法选择器在运行时自动映射到类。
IMP的简单使用
注意:修改Enable Strict Checking of objc_msgSend Calls
为NO,不强制检查IMP类型。
模拟网络请求回调,创建AViewModel,定义- (void)requestData:(NSString *)cls
方法,通过类名和方法名获取指向方法实现的指针(IMP),调用IMP传值给AViewController。
AViewController
- (IBAction)buttonClick:(UIButton *)sender {
AViewModel *viewmodel = [[AViewModel alloc]init];
[viewmodel requestData: NSStringFromClass(self.class)];
}
- (void)responseData: (NSString *)result {
NSLog(@"%s --- %@", __func__, result);
}
AViewModel
- (void)requestData:(NSString *)cls {
Class class = NSClassFromString(cls);
SEL sel = NSSelectorFromString(@"responseData:");
Method method = class_getInstanceMethod(class, sel);
IMP imp = method_getImplementation(method);
imp(class, sel, @"s");
}
使用IMP的好处:解耦,AViewModel调用AViewController的方法,不需要知道AViewController
缺点:字符串的方式接受类名和方法名,没有编译期的检查,方法名写错会造成运行时崩溃。