前言:
目录:
(1)使用class_replaceMethod/class_addMethod函数在运行时对函数进行动态替换或增加新函数
(2)重载forwardingTargetForSelec
(3)重载resolveInstanceMethod,从而在无法处理某个selector时,动态添加一个selector
(4)使用class_copyPropertyList及property_getName获取类的属性列表及每个属性的名称
(1)在运行时对函数进行动态替换 : class_replaceMethod
示例代码:
IMP orginIMP; NSString * MyUppercaseString(id SELF, SEL _cmd) { NSLog(@"begin uppercaseString"); NSString *str = orginIMP (SELF, _cmd);(3) NSLog(@"end uppercaseString"); return str; } -(void)testReplaceMethod { Class strcls =[NSString class]; SEL oriUppercaseString = @selector(uppercaseString); orginIMP = [NSStringinstanceMethodForSelector:oriUppercaseString]; (1) IMP imp2 = class_replaceMethod(strcls,oriUppercaseString,(IMP)MyUppercaseString,NULL);(2) NSString *s = "hello world"; NSLog(@"%@",[s uppercaseString]]; }
执行结果为:
begin uppercaseString
end uppercaseString
HELLO WORLD
这段代码的作用就是
(1)得到uppercaseString这个函数的函数指针存到变量orginIMP中
(2)将NSString类中的uppercaseString函数的实现替换为自己定义的MyUppercaseString
(3)在MyUppercaseString中,先执行了自己的log代码,然后再调用之前保存的 uppercaseString的系统实现,这样就在系统函数执行之前加入自己的东西,后面每次对NSString调用uppercaseString的 时候,都会打印出log来
(2)当某个对象不能接受某个selector时,将对该selector的调用转发给另一个对象:- (id)forwardingTargetForSelec
示例代码:
1 @interface CA : NSObject 3 -(void)f; 4 5 @end 6 7 @implementation CA 8 9 - (id)forwardingTargetForSelector:(SEL)aSelector 11 { 13 if (aSelector ==@selector(uppercaseString)) 15 { 17 return@"hello world"; 19 } 21 }
测试代码:
CA *a = [CA new]; NSString * s = [a performSelector:@selector(uppercaseString)]; NSLog(@"%@",s);
测试代码的输出为:HELLO WORLD
(3)当某个对象不能接受某个selector时,向对象所属的类动态添加所需的selector:
+ (BOOL) resolveInstanceMethod:(SEL)aSEL
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
|
代码示例一:
1
@implementation
CA
3
void
dynamicMethodIMP(
id
self
,
SEL
_cmd)
5 {
7
"SEL %s did not exist\n"
,sel_getName(_cmd));
9 }
10
11 + (
BOOL
) resolveInstanceMethod:(
SEL
)aSEL
13 {
15
if
(aSEL ==
@selector
(t))
17
19
"v@:"
);
21
return
YES
;
23
25
return
[superresolveInstanceMeth
27 }
28
29
@end
测试代码:
CA * ca = [CA
new
]
[ca performSelector:
@selector
(t)];
|
执行结果
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
示例代码二:
@implementation
CA
void
dynamicMethodIMP(
id
self
,
SEL
_cmd)
{
printf(
"SEL %s did not exist\n"
,sel_getName(_cmd));
}
+ (
BOOL
) resolveInstanceMethod:(
SEL
)aSEL
{
return
YES
;
}
- (
id
)forwardingTargetForSelec
SEL
)aSelector
{
if
(aSelector ==
@selector
(uppercaseString))
{
return
@
"hello world"
;
}
}
测试代码 :
a = [[CA alloc]init];
NSLog
(@
"%@"
,[a performSelector:
@selector
(uppercaseString)];
|
该测试代码的输出为:HELLO WORLD
对于该测试代码,由于a没有uppercaseString函数,因此会触发resolveInstanceMethod,但是由于该函数并没有添加selector,因此运行时发现找不到该函数,会触发
forwardingTargetForSelec
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
示例代码三:
@implementation
CA
+ (
BOOL
) resolveInstanceMethod:(
SEL
)aSEL
{
return
YES
;
}
- (
id
)forwardingTargetForSelec
SEL
)aSelector
{
return
nil
;
}
测试代码:
1
2
NSLog
(@
"%@"
,[a performSelector:
@selector
(uppercaseString)];
|
这段代码的执行顺序为:
(2)等测试代码执行时,forwardingTargetForSelec
(3)由于forwardingTargetForSelec
(4) 使用class_copyPropertyList及property_getName获取类的属性列表及每个属性的名称
u_int
objc_property_t*
class
], &count);
for
(
int
i = 0; i < count ; i++)
{
const
char
* propertyName = property_getName(properties[i]);
NSString
*strName = [
NSString
stringWithCString:propertyName encoding:
NSUTF8StringEncoding
];
NSLog
(@
"%@"
,strName);
}
|
以上代码获取了UIView的所有属性并打印属性名称, 输出结果为:
skipsSubviewEnumeration
viewTraversalMark
viewDelegate
monitorsSubtree
backgroundColorSystemCol
gesturesEnabled
deliversTouchesForGestur
userInteractionEnabled
tag
layer
_boundsWidthVariable
_boundsHeightVariable
_minXVariable
_minYVariable
_internalConstraints
_dependentConstraints
_constraintsExceptingSubv
_shouldArchiveUIAppearanc
|
(5) 使用class_copyMethodList获取类的所有方法列表
u_int
Method*
class
], &count);
for
(
int
i = 0; i < count ; i++)
{
SEL
name = method_getName(methods[i]);
NSString
*strName = [
NSString
stringWithCString:sel_getName(name) encoding:
NSUTF8StringEncoding
];
NSLog
(@
"%@"
,strName);
}
|
代码执行后将输出UIView所有函数的名称,具体结果略。
1.SEL method_getName(Method m) 由Method得到SEL 2.IMP method_getImplementation(Method m) 由Method得到IMP函数指针 3.const char*method_getTypeEncoding(Method m) 由Method得到类型编码信息 4.unsigned intmethod_getNumberOfArguments(Method m)获取参数个数 5.char*method_copyReturnType(Method m) 得到返回值类型名称 6.IMP method_setImplementation(Method m, IMP imp) 为该方法设置一个新的实现
-
增加
增加函数:class_addMethod
增加实例变量:class_addIvar
增加属性:
@dynamic
标签,或者class_addMethod,因为属性其实就是由getter和setter函数组成
增加Protocol:class_addProtocol (说实话我真不知道动态增加一个protocol有什么用,-_-!!)
|
-
获取
获取函数列表及每个函数的信息(函数指针、函数名等等):class_getClassMethod method_getName ...
获取属性列表及每个属性的信息:class_copyPropertyList property_getName
获取类本身的信息,如类名等:class_getName class_getInstanceSize
获取变量列表及变量信息:class_copyIvarList
获取变量的值
|
-
替换
将实例替换成另一个类:object_setClass
将函数替换成一个函数实现:class_replaceMethod
直接通过
char
*格式的名称来修改变量的值,而不是通过变量
|