一 方法调用的本质
1.runtime 的使用方法 ,首先导入objc/message.h ,在build setting 里面输入msg 设置为NO 因为从xcode5开始苹果不推荐使用底层的东西了擦!! runtime是运行时的机制,也就是说所有方法的调用在编译command+b的时候不会真正检测到底调用谁,只会在运行时候(动态)调用方法 ,方法调用的本质顺序; e.g.
[p eat] ---> [p performselector:@selector:eat] -> objc_msgsend(p,@selector:eat);
[Person eat] --> 先转化成类对象 Class personClass = [Person Class]; --> [personClass eat] --> [personClass performselector:@selector:eat]; ---> objc_msgsend([Person Class],@selector:eat);
无论是类调用放还是类对象调用方法本质都是 转化成objc_msgsend
- (void)text1 {
person *p = [[person alloc] init];
// xcode5 之后使用运行时方法
// 苹果不推荐调用底层的方法
// 在 buildsettings 搜索msg 设置为NO
// 让p 发送消息
objc_msgSend(p, @selector(eat));
//
objc_msgSend([person class], @selector(eat)); // 类对象
// 类名调用类方法 其实就是用类对象调用方法
[person eat];
// 获取类对象
Class personClass = [person class];
[personClass performSelector:@selector(eat)];
[personClass eat];
}
二 交换方法的实现
本质先得到两个方法 然后交换两个方法的实现请见官方文档
开发时候的作用很大比如更改文字的大小颜色等等替换官方的方法实现换成自己的但是记得回调官方的方法哦!! 这样可以替换所有的方法如果用分类的方法只能替换将来的已经使用的方法就没办法了一劳永逸!!! 装逼利器!
/**
* Sets the implementation of a method.
*
* @param m The method for which to set an implementation.
* @param imp The implemention to set to this method.
*
* @return The previous implementation of the method.
*/
OBJC_EXPORT IMP method_setImplementation(Method m, IMP imp)
__OSX_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_2_0);
/**
* Exchanges the implementations of two methods.
*
* @param m1 Method to exchange with second method.
* @param m2 Method to exchange with first method.
*
* @note This is an atomic version of the following:
* \code
* IMP imp1 = method_getImplementation(m1);
* IMP imp2 = method_getImplementation(m2);
* method_setImplementation(m1, imp2);
* method_setImplementation(m2, imp1);
* \endcode
*/
OBJC_EXPORT void method_exchangeImplementations(Method m1, Method m2)
__OSX_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_2_0);
#import "UIImage+myImage.h"
#import <objc/message.h>
@implementation UIImage (myImage)
+ (void)load {
// 方法和属性等都是在类中所以用class_
Method m1 = class_getClassMethod([UIImage class], @selector(imageNamed:));
Method m2 = class_getClassMethod([UIImage class], @selector(stimageNamed:));
method_exchangeImplementations(m1 , m2 );
}
+ (UIImage *)stimageNamed:(NSString *)imageName {
UIImage *image = [UIImage stimageNamed:imageName];
if (image ==nil) {
NSLog(@"图片为nil");
}
return image;
}
三 动态的为某个类添加方法的实现
class_addMethod(self , @selector(eat:), (IMP)eatsssss, "v@:@");
#import "person.h"
#import <objc/message.h>
@implementation person
// 调用了一个没有实现的方法就会调用这个方法 可以知道哪些方法没有实现 self _cmd //隐私参数
+ (BOOL)resolveInstanceMethod:(SEL)sel {
// 动态添加方法
if ([NSStringFromSelector(sel) isEqualToString:@"eat:"]) {
/**
cls: 给哪个类添加方法
SEL:添加方法的方法编号
IMP:函数名 方法实现 函数入口
types : 方法类型
*/
class_addMethod(self , @selector(eat:), (IMP)eatsssss, "v@:@");
}
return [super resolveInstanceMethod:sel];
}
// 定义函数
void eatsssss (id self ,SEL _cmd,id parames)
{
NSLog(@"hahha%@",parames);
}
官方文档
Dynamic Method Resolution
There are situations where you might want to provide an implementation of a method dynamically. For example, the Objective-C declared properties feature (see Declared Properties in The Objective-C Programming Language) includes the @dynamic directive:
@dynamic propertyName;
which tells the compiler that the methods associated with the property will be provided dynamically.
You can implement the methods resolveInstanceMethod: and resolveClassMethod: to dynamically provide an implementation for a given selector for an instance and class method respectively.
An Objective-C method is simply a C function that take at least two arguments—self and _cmd. You can add a function to a class as a method using the function class_addMethod. Therefore, given the following function:
void dynamicMethodIMP(id self, SEL _cmd) {
// implementation ....
}
you can dynamically add it to a class as a method (called resolveThisMethodDynamically) using resolveInstanceMethod: like this:
@implementation MyClass
+ (BOOL)resolveInstanceMethod:(SEL)aSEL
{
if (aSEL == @selector(resolveThisMethodDynamically)) {
class_addMethod([self class], aSEL, (IMP) dynamicMethodIMP, "v@:");
return YES;
}
return [super resolveInstanceMethod:aSEL];
}
@end
Forwarding methods (as described in Message Forwarding) and dynamic method resolution are, largely, orthogonal. A class has the opportunity to dynamically resolve a method before the forwarding mechanism kicks in. If respondsToSelector: or instancesRespondToSelector: is invoked, the dynamic method resolver is given the opportunity to provide an IMP for the selector first. If you implement resolveInstanceMethod: but want particular selectors to actually be forwarded via the forwarding mechanism, you return NO for those selectors.
Dynamic Loading
An Objective-C program can load and link new classes and categories while it’s running. The new code is incorporated into the program and treated identically to classes and categories loaded at the start.
Dynamic loading can be used to do a lot of different things. For example, the various modules in the System Preferences application are dynamically loaded.
In the Cocoa environment, dynamic loading is commonly used to allow applications to be customized. Others can write modules that your program loads at runtime—much as Interface Builder loads custom palettes and the OS X System Preferences application loads custom preference modules. The loadable modules extend what your application can do. They contribute to it in ways that you permit but could not have anticipated or defined yourself. You provide the framework, but others provide the code.
Although there is a runtime function that performs dynamic loading of Objective-C modules in Mach-O files (objc_loadModules, defined in objc/objc-load.h), Cocoa’s NSBundle class provides a significantly more convenient interface for dynamic loading—one that’s object-oriented and integrated with related services. See the NSBundle class specification in the Foundation framework reference for information on the NSBundle class and its use. See OS X ABI Mach-O File Format Reference for information on Mach-O files.
四 动态的为某个类添加属性
#import "NSObject+name.h"
#import <objc/message.h>
// @property在分类里面只会生成方法的set get方法的生明不会生成实现和_成员变量
@implementation NSObject (name)
- (void)setName:(NSString *)name {
// 添加属性一般也给对象添加的 objc
/***
objc 给哪个对象添加属性
key 属性名 根据key 去获取关联的对象 void * == id
value 关联的值赋给的值name
policy weak retain copy
*/
objc_setAssociatedObject(self, @"name", name, OBJC_ASSOCIATION_COPY);
}
- (NSString *)name {
return objc_getAssociatedObject(self, @"name");
}