runtime-objc_msgSend
2017-01-18 19:44
253 查看
[TOC]
前言: 本文十分基础
这篇文章讲讲怎么用
中间打红的部分是路径,最简单的办法就是把.m文件直接拖到终端.我敲下回车,发现报错,
上面的不行,我去创建了一个新工程:
这里选择Command Line Tool.
然后这里只有一个main.m文件,我在这个文件里面添了简单的几行代码,main.m文件看起来是下面这个样子:
OK,我这里有个细节,就是在桌面创建了一个名为clang的文件夹,如果你直接打开终端,那么你的所在的路径是在根目录下的用户.为什么要说这个,因为你使用
首先打开终端,输入如命令
运行到这里就OK了,我们可以用
我这里生成的main.m文件有3M大,我猜想是把Foundation框架都转成了C源码.9.5W行代码��.
直接
我是如何找到这个main函数在最下面?是我看书上的图片,显示的就是
OK,到了这一步,C语言的源码暴露在我们面前了,到这里,就可以比葫芦画瓢,试着用
我们可以使用objc_msgSend来修改.
只需要对比着
嗯..
前言: 本文十分基础
这篇文章讲讲怎么用
objc_msgSend,配合一个小小的案例,不光光讲怎样用,我会把我是如何学到
objc_msgSend这一系列的过程.很多时候,我们看别人的文章,只会给你将结果,很少会讲这个结果究竟是怎样得出来的,OK,言归正传.
runtime,大家都知道这个运行时库,在运行的时候,会把OC代码转为C,然后执行.OK,熟记于心,怎样转?我不会,那么
objc_msgSend我也知道这个API,是
runtime库里面的,可是大家是如何知道的?我不知道.
起因
最近在看一本书,书上讲到把OC代码转换为C源码,这里有个终端命令clang -rewrite-objc <filename.m>我试着在终端上敲如下命令:
中间打红的部分是路径,最简单的办法就是把.m文件直接拖到终端.我敲下回车,发现报错,
'UIKit/UIKit.h' file not found这个问题我现在还没找到解决的办法.
上面的不行,我去创建了一个新工程:
这里选择Command Line Tool.
然后这里只有一个main.m文件,我在这个文件里面添了简单的几行代码,main.m文件看起来是下面这个样子:
#import <Foundation/Foundation.h> int main(int argc, const char * argv[]) { @autoreleasepool { NSString * str = @"123"; [str stringByAppendingString:@"456"]; } return 0; }
OK,我这里有个细节,就是在桌面创建了一个名为clang的文件夹,如果你直接打开终端,那么你的所在的路径是在根目录下的用户.为什么要说这个,因为你使用
clang -rewrite-objc <filename.m>这个命令,它会在当前目录下生产一个main.cpp的文件.这个就是我们的目标文件.
首先打开终端,输入如命令
clang -rewrite-objc main.m,这里我直接把工程里面的main.m文件复制到桌面的
clang文件夹里面了,然后按下回车,我这里会输出很多warning:
运行到这里就OK了,我们可以用
open .命令打开
clang文件夹,会看到里面多了个main.m文件.
我这里生成的main.m文件有3M大,我猜想是把Foundation框架都转成了C源码.9.5W行代码��.
直接
command+↓跳到文件的最下面,可以看到
int main()这个main函数,函数体内,就是我关注的东西了.
我是如何找到这个main函数在最下面?是我看书上的图片,显示的就是
int main(...,我就直接搜索了一下这个
int main的位置,代码如下:
int main(int argc, const char * argv[]) { /* @autoreleasepool */ { __AtAutoreleasePool __autoreleasepool; NSString * str = (NSString *)&__NSConstantStringImpl__var_folders_6q_7tzk06yx4fd147m641v6dnsw0000gn_T_main_4f05b0_mi_0; ((NSString *(*)(id, SEL, NSString *))(void *)objc_msgSend)((id)str, sel_registerName("stringByAppendingString:"), (NSString *)&__NSConstantStringImpl__var_folders_6q_7tzk06yx4fd147m641v6dnsw0000gn_T_main_4f05b0_mi_1); } return 0; }
OK,到了这一步,C语言的源码暴露在我们面前了,到这里,就可以比葫芦画瓢,试着用
objc_msgSend来做一些没有
objc_msgSend它不能做的事情咯.
#import "ViewController.h" #import "UIAlertAction+SLAlertAction.h" #import <objc/message.h> @interface ViewController () @end @implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; } - (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event { __block UIAlertController *alertVc = [self tipWithTitle:@"你好吗" Message:@"我不好"]; [self presentViewController:alertVc animated:YES completion:nil]; dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ NSLog(@"aaa"); alertVc.title = @"heelo"; ((UIAlertAction *(*)(id, SEL, NSString *))(void *)objc_msgSend)((id)alertVc.actions.firstObject, @selector(setTitle:), @"hello"); }); } - (UIAlertController *)tipWithTitle:(NSString *)title Message:(NSString *)message { UIAlertController *alertVc = [UIAlertController alertControllerWithTitle:title message:message preferredStyle:UIAlertControllerStyleAlert]; UIAlertAction *firm = [UIAlertAction sl_alertActionWithType:HYBVerifyAlertActionConfirm navController:nil refuseMessage:nil]; UIAlertAction *cancel = [UIAlertAction sl_alertActionWithType:HYBVerifyAlertActionCancel navController:nil refuseMessage:nil]; [alertVc addAction:cancel]; [alertVc addAction:firm]; return alertVc; } - (void)didReceiveMemoryWarning { [super didReceiveMemoryWarning]; // Dispose of any resources that can be recreated. } @end
UIAlertAction的
title是个只读属性,但是我想在弹窗弹出,3秒后进行修改
取消两字为
heelo.这里我用了一个UIAlertAction的分类.其实就是添加了一个取消一个确定按钮.
我们可以使用objc_msgSend来修改.
只需要对比着
((NSString *(*)(id, SEL, NSString *))(void *)objc_msgSend)((id)str, sel_registerName("stringByAppendingString:"), (NSString *)&__NSConstantStringImpl__var_folders_6q_7tzk06yx4fd147m641v6dnsw0000gn_T_main_4f05b0_mi_1);这行代码敲就可以了!
嗯..
相关文章推荐
- Objective-C Runtime分析(三)-objc_msgSend
- 《Objective-C Runtime分析(三)-objc_msgSend》
- runtime - 消息发送(objc_msgSend)
- iOS runtime ~ objc_setAssociatedObject 函数关键策略
- objc_msgSend(): Too many arguments to function call ,expected 0,have3
- 为什么程序会在objc_msgSend() 崩溃
- objc runtime 动态增加属性
- 利用objc runtime 和 KVC 对自定义对象归档解档
- Effective Objective-C 2.0 编写高质量iOS与OS X代码 objc_msgSend 的作用
- objc_msgSend()报错Too many arguments to function call ,expected 0,have3
- objc_runtime给类目添加属性关联(objc_setAssociatedObject、objc_getAssociatedObject)
- libcpmt.lib (xxx.obj) LNK2038: mismatch detected for 'RuntimeLibrary': value 'MT_StaticRelease' doesn't match value 'MD_DynamicRelease' in XXX.obj
- iOS objc_msgSend 报错解决方案
- Swift 调用 objc/runtime OBJC_ASSOCIATION_RETAIN
- Objective-C Runtime 【objc_msgSend函数】
- objc runtime 动态增加属性
- objc/runtime.h 相关
- Effective Objective-C 2.0 编写高质量iOS与OS X代码 objc_msgSend 的作用
- block为什么用copy?利用runtime运行时的objc_方法为分类扩充成员变量
- iOS objc_msgSend 野指针Crash 从 Log 提取 Crash 时 selector 的地址和名字并打印