MangoFix:iOS热修复另辟蹊径

今天向大家介绍的是iOS热修复的另一解决方案:MangoFix。介绍他的原因是他和传统的iOS热修复使用JavaScript bridge 的方式完全不同,MangoFix是一个语法和OC语法非常类似的DSL,其语言本身的设计目标就是为了解决iOS热修复问题,所以在使用的便捷程度和性能方面都要远远超过传统的iOS 热修复SDK,比如JSPatch。下面从以下几点介绍MangoFix,更具体的请参考GitHub文档和MangoFix单元测试。

1、如何加载一个MangoFix脚本

  • 1 首先通过CocoaPods安装MangoFix :pod 'MangoFix'

  • 2 引入MangoFix头文件:#import <MangoFix/MangoFix.h>

  • 3 创建MangoFix脚本执行上下文对象MFContext实例

  • 4 运行MangoFix脚本文件

示例代码如下:

    NSString *path = [[NSBundle mainBundle] pathForResource:@"demo" ofType:@"mg"];NSURL *scriptUrl = [NSURL fileURLWithPath:path];MFContext *context = [[MFContext alloc] init];[context evalMangoScriptWithURL:scriptUrl];
复制代码

2、MangoFix如何修复OC对象(类)方法

MangoFix可以替换或创建任意OC对象实例方法或类方法,语法和OC类似,不过在类的定义上采用class关键字。下面示例:

class MFInstanceMethodReplaceTest : NSObject {- (BOOL)testInstanceMethodReplace{return YES;
}}
复制代码

对于类方法的替换只需将方法返回值类型前的-修改为+即可。
需要注意的是:
1、继承的父类不可以省略。

3、MangoFix如何为对象添加属性

MangoFix中为对象添加属性和OC一样,支持的修饰符有: weakstrongcopyassignnonatomicatomic。下面看一下示例代码:

class MFObjectPropertyTest : NSObject{@property(nonatomic, copy)NSString *propertyName;- (NSString *)testObjectPropertyTest{return self.strTypeProperty;
}}
复制代码

需要注意的是:
1、属性不支持class修饰符。
2、MangoFix是通过objc_setAssociatedObject实现属性值的存储,但是MangoFix在解析时候做了处理,访问属性值也可以通过_propertyName这种方式进行访问。

4、MangoFix中如何使用block

在MangoFix对OC中block类型声明过于复杂做了简化,用Block关键字表示block类型,block的定义则和OC相同,示例代码如下:

class MFMethodParameterListAndReturnValueTest : NSObject{- (Block)testMethodParameterListAndReturnValueWithString:(NSString *)str block:(Block)block{NSMutableDictionary *dic = @{}.mutableCopy();dic[@"param1"] = str + @"MangoFix";dic[@"param2"] = block(@"MangoFix");Block retBlock = ^NSDictionary *(/*不能加void*/){return dic;};return retBlock;
}}
复制代码

需要注意的是:
1、在无参block定义时,不可以加void声明。
2、Block关键字后面不需要加*运算符。

5、如何解决Block循环引用问题

MangoFix在1.1.7版本中添加__weak__strong变量修饰符,可以像OC原生一样解决Block循环引用问题,使用示例如下:

@interface MyController : UIViewController@property(nonatomic,copy) id block;@end
复制代码
class MyController: UIViewController {
- (void)viewDidLoad {super.viewDidLoad();__weak id weakSelf = self;self.block = ^{__strong id strongSelf = weakSelf;NSLog(weakSelf);};
}}
复制代码

上部分是OC代码,下部分是MangoFix代码,需要注意的是,__weak__strong只能放在变量类型之前。

6、MangoFix中如何使用GCD

MangoFix中已经内置的GCD API,使用方法和 OC相同,对于需要扩展的C函数,可以参考下面如何在MangoFix中注入全局对象的描述,GCD使用示例如下:

class MFGCDTest : NSObject {- (void)testGCDWithCompletionBlock:(Block)completion{dispatch_queue_t queue = dispatch_queue_create("com.plliang19.mango", DISPATCH_QUEUE_SERIAL);dispatch_async(queue, ^{completion(@"success");});
}- (void)testGCDAfterWithCompletionBlock:(Block)completion{dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 3 * NSEC_PER_SEC), dispatch_get_main_queue(), ^{completion(@"success");});
}}class MFDispatchSourceTest : NSObject{- (NSInteger)testDispatchSource{NSInteger count = 0;dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);dispatch_source_t timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, dispatch_get_global_queue(0, 0));dispatch_source_set_timer(timer, DISPATCH_TIME_NOW, 0.5 * NSEC_PER_SEC, 0 * NSEC_PER_SEC);dispatch_source_set_event_handler(timer, ^{count++;if (count == 10) {dispatch_suspend(timer);dispatch_semaphore_signal(semaphore);}});dispatch_resume(timer);dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);return count;
}}复制代码

7、static变量支持

MangoFix1.2.0版本中增加了对static变量进行了支持,MangoFix 的static变量和C语言中static变量特性基本一致。MangoFix中通过一张全局表对static变量进行管理,static变量只会初始化一致,static变量生命周期为从第一次初始化到App退出,static变量作用域和自动变量作用域一致,所以可以在不同作用域范围内,创建变量名相同的static变量也是不会冲突的。

8、取地址运算符

MangoFix1.2.0版本中,增加了对取地址运算符&的支持,利用取地址运算符和static变量,MangoFix便能对GCD中的dispatch_once函数做很好的支持,比如下面的MangoFix示例代码:

class MFGetAddressOperatorTest : NSObject{- (NSInteger)testGetAddressOperator{static int i = 0;static dispatch_once_t onceToken;dispatch_once(&onceToken, ^{i++;});return i;
}}
复制代码

9、如何在MangoFix中注入全局对象

MangoFix中MFContext对象提供了 - (void)setObject:(MFValue *)value forKeyedSubscript:(NSObject <NSCopying> *)key;方法,便于用户向执行上下文中注入全局对象,比如在OC代码中执行下面代码:

context[@"globalVar"] = [MFValue valueInstanceWithBOOL:YES];
context[@"MyLog"] = [MFValue valueInstanceWithBlock:^void (id obj){NSLog(@"%@",obj);}];
复制代码

分别表示向context注入全局的BOOL变量globalVar和名为MyLog的block。

10、MangoFix中如何针对不同App版本做不同的热修复处理

MangoFix提供了条件注解#If(conditionExpr),可以在运行时做判断注解所作用的类、属性、方法是否使能,先看一下示例代码:

class MFConditionalReplaceTest : NSObject{#If($systemVersion.doubleValue() >= 10.0 )
- (BOOL)testConditionalReplace{return NO;
}}
复制代码

上面代码表示只有当$systemVersion.doubleValue()值大于10.0才会对 - (BOOL)testConditionalReplace方法进行替换。 MangoFxi中已经内置了$systemVersion$appVersion$buildVersion等和版本相关的全局变量,分别表示:[UIDevice currentDevice].systemVersionCFBundleShortVersionStringCFBundleVersion,当然如果用户觉得不够还可以自己向MangoFix执行上下文中注入自定义的全局变量。

11、C函数变量

早期MangoFix版本中已经将一些常用的C函数进行预埋,用户也可以自定义进行预埋,但是总有一些需要调用的C函数没有预埋到,所以MangoFix 1.3.0版本开始支持C函数变量,可以做到C函数声明即用无需预埋,C函数变量的定义和其他语言中的泛型很类似,格式如: CFunction<returnType,arg1Type,arg2Type,...> func, 尖括号中第一个type是函数返回值类型,其他的为函数形参类型,现在支持的类型有:voidBOOLintlongint8_tint16_tint32_tint64_tu_intu_longu_int8_t```、u_int16_tu_int32_tu_int64_tsize_tfloatdoubleCGFloatchar *void *idSELClassstruct structName,对于其他数据类型,要根据数据类型的大小选择上面一种数据类型,而C函数变量的值用CFunction("function_name")获取,对于dlsymdlopen这两个函数已被禁止动态调用,另外要注意的是CFunction("function_name")``只支持获取动态链接的C函数。 下面我们看一段示例代码:

int NSDocumentDirectory = 9;
int NSUserDomainMask = 1;int  O_WRONLY = 0x0001;
uint S_IRWXU  = 0000700;CFunction<id, int, int, BOOL> NSSearchPathForDirectoriesInDomains = CFunction("NSSearchPathForDirectoriesInDomains");
CFunction<int, char *, int, int> open = CFunction("open");
CFunction<size_t, int, void *, size_t> write = CFunction("write");
CFunction<int, int> close = CFunction("close");class  MFFuncDeclareTest : NSObject{- (void)testFuncDeclare{NSString *doc = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES).lastObject;NSString *path = doc.stringByAppendingPathComponent:(@"MangoFxi.html");NSFileManager *fileManager = NSFileManager.defaultManager();if (!fileManager.fileExistsAtPath:(path)) {BOOL ret = fileManager.createFileAtPath:contents:attributes:(path, nil, nil);if (!ret) {NSLog(@"创建文件失败");return;}}NSLog(path);int fd = open(path.UTF8String,O_WRONLY, S_IRWXU);if (fd < 0) {NSLog(@"打开文件失败");return;}NSURL *url = NSURL.URLWithString:(@"https://github.com/YPLiang19/Mango");NSData *data = NSData.dataWithContentsOfURL:(url);write(fd, data.bytes, data.length);close(fd);
}}复制代码

12、类型别名

MangoFix 1.3.0版本开始支持 typedef功能,格式为:typedef existingType newType; 比如:

typedef long alias_long;
alias_long var = 10;
复制代码

13、MangoFix中自定义结构体的使用要注意什么

MangoFix脚本中使用结构体,原则上是要先对结构体使用declare struct进行声明,但是MangoFix已经对常用的结构已经内置声明,已内置声明的结构如下: CGPointCGSizeCGRectCGAffineTransformCGVectorNSRangeUIOffsetUIEdgeInsetsCATransform3D

在MangoFix中使用未声明的结构体,需要做如下声明:

declare struct MFCustomStruct {typeEncoding:"{MFCustomStruct=dd}",//@encode(struct MFCustomStruct)keys:x,y
}
复制代码

特别需要注意的是:
1、在定义一个结构体变量时,需要在前面加入struct关键字:

  struct  UIEdgeInsets padding = UIEdgeInsetsMake(10, 10, 10, 10);
复制代码

14、Masonry链式编程方式在MangoFix中如何编写

有同学疑问对Masonry中的链式编程在MangoFix如何编写呢?其实这个写起来也是大同小异。需要注意的是,在MangoFix中对调用的方法如果是无参的,那么可以省去调用后面的一对括号,但是如果方法返回的是一个block对象,那么这对括号就不能省略,应为此时如果省略了方法调用括号,那么MangoFix解析器就无法知道,此时用户是想调用OC的对象方法,还是调用方法返回的block。下面是一个OC和MangoFix分别调用Masonry官方示例代码的对比:

UIView *superview = self.view;UIView *view1 = [[UIView alloc] init];view1.translatesAutoresizingMaskIntoConstraints = NO;view1.backgroundColor = [UIColor greenColor];[superview addSubview:view1];UIEdgeInsets padding = UIEdgeInsetsMake(10, 10, 10, 10);[view1 mas_makeConstraints:^(MASConstraintMaker *make) {make.top.equalTo(superview.mas_top).with.offset(padding.top); //with is an optional semantic fillermake.left.equalTo(superview.mas_left).with.offset(padding.left);make.bottom.equalTo(superview.mas_bottom).with.offset(-padding.bottom);make.right.equalTo(superview.mas_right).with.offset(-padding.right);}];
复制代码
    UIView *superview = self.view;UIView *view1 = UIView.alloc().init();view1.translatesAutoresizingMaskIntoConstraints = NO;view1.backgroundColor = UIColor.greenColor();superview.addSubview:(view1);struct  UIEdgeInsets padding = UIEdgeInsetsMake(10, 10, 10, 10);view1.mas_makeConstraints:(^(MASConstraintMaker *make) {make.top.equalTo()(superview.mas_top).with.offset()(padding.top); //with is an optional semantic fillermake.left.equalTo()(superview.mas_left).with.offset()(padding.left);make.bottom.equalTo()(superview.mas_bottom).with.offset()(-padding.bottom);make.right.equalTo()(superview.mas_right).with.offset()(-padding.right);});
复制代码

上面部分是OC代码,下面部分是MangoFix代码,主要区别就是MangoFix代码在equalTooffset后面多了一对括号,就是避免MangoFix解析器产生歧义。再者就是MangoFix中UIEdgeInsets前的struct关键字不能省略。

15、MangoFix性能的如何

根据本人测试,MangoFix的初始化速度是JSPatch的10倍左右,运行速度是JSPatch的2~5倍,内存占用方面并无太大区别。

16、MangoFix还有哪些不足

  • MangoFix不支持可变参数方法的调用和替换。
  • MangoFix调用C函数,需要预先通过注入全局对象方式,通过block将C函数预先埋入(1.3.0版本已支持C函数变量声明即用无需预埋)。
  • MangoFix不支持替换C函数。

转载于作者:知水为命
链接:www.jianshu.com/p/7ae91a2da…

给大家推荐一个优秀的iOS交流群,群里的伙伴们都是非常优秀的iOS开发人员,我们专注于技术的分享与技巧的交流,大家可以在群讨论技术,交流学习。欢迎大家的加入761407670(密码123)。

转载于:https://juejin.im/post/5d20448cf265da1bbc6ff6bc

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/248585.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

看完这篇文章保你面试稳操胜券——基础篇(html/css)

✨ 进大厂收藏这一系列就够了,全方位搜集总结,为大家归纳出这篇面试宝典,面试途中祝你一臂之力!,共分为四个系列 ✨ 本 篇 为 《 看 完 这 篇 文 章 保 你 面 试 稳 操 胜 券 》 第 二 篇 ( h

《深入理解Spark-核心思想与源码分析》(四)第四章存储体系

天行健&#xff0c;君子以自强不息&#xff1b;地势坤&#xff0c;君子以厚德载物。——《易经》 本章导读 Spark的初始化阶段、任务提交阶段、执行阶段&#xff0c;始终离不开存储体系。 Spark为了避免Hadoop读写磁盘的I/O操作成为性能瓶颈&#xff0c;优先将配置信息、计算结…

看完这篇文章保你面试稳操胜券 ——(必考题)javaScript 篇

✨ 进大厂收藏这一系列就够了,全方位搜集总结,为大家归纳出这篇面试宝典,面试途中祝你一臂之力!,共分为四个系列 ✨ 本 篇 为 《 看 完 这 篇 文 章 保 你 面 试 稳 操 胜 券 》 第 三 篇 ( j

Django打造大型企业官网-项目部署

Django打造大型企业官网-项目部署 一、准备工作 1、在开发机上的准备工作 1&#xff09;确认项目没有bug。 2&#xff09;打开终端&#xff0c;进入虚拟环境&#xff0c;再 cd 到项目根目录下&#xff0c;执行命令&#xff1a;pip freeze > requirements.txt&#xff0c;将…

2019.01.26 codeforces 1096G. Lucky Tickets(生成函数)

传送门 题意简述&#xff1a;现在有一些号码由000~999中的某些数字组成&#xff08;会给出&#xff09;&#xff0c;号码总长度为nnn&#xff0c;问有多少个号码满足前n2\frac n22n​个数码的和等于后n2\frac n22n​个数码的和&#xff08;保证nnn是偶数&#xff09;&#xff0…

看完这篇文章保你面试稳操胜券——小程序篇

✨ 进大厂收藏这一系列就够了,全方位搜集总结,为大家归纳出这篇面试宝典,面试途中祝你一臂之力!,共分为四个系列 ✨ 本 篇 为 《 看 完 这 篇 文 章 保 你 面 试 稳 操 胜 券 》 第 四 篇 ( 微

17 | 如何正确地显示随机消息?

我在上一篇文章&#xff0c;为你讲解完order by语句的几种执行模式后&#xff0c;就想到了之前一个做英语学习App的朋友碰到过的一个性能问题。今天这篇文章&#xff0c;我就从这个性能问题说起&#xff0c;和你说说MySQL中的另外一种排序需求&#xff0c;希望能够加深你对MySQ…

看完这篇文章保你面试稳操胜券——React篇

✨ 进大厂收藏这一系列就够了,全方位搜集总结,为大家归纳出这篇面试宝典,面试途中祝你一臂之力!,共分为四个系列 ✨ 本 篇 为 《 看 完 这 篇 文 章 保 你 面 试 稳 操 胜 券 》 第 五 篇 ( r

HTML的footer置于页面最底部

vue项目中&#xff0c;使用element-ui的布局&#xff0c;仍然出现footer不固定页面底部的情况&#xff0c;网上找到的一个管用的 方法是&#xff1a;footer高度固定绝对定位 <html><head></head><body><div class"header">header</…

logstash异常

logstash异常 123Unrecognized VM option UseParNewGCError: Could not create the Java Virtual Machine.Error: A fatal exception has occurred. Program will exit.logstash的版本6.4.1&#xff0c;修改config/jvm.options&#xff0c;注释掉-XX:UseParNewGC这个配置即可。…

QT+VS中使用qDebbug()打印调试信息无法显示

首先右键点击项目名称&#xff0c;找到最后一项属性 然后依次设置为如图所示即可 再次编译后&#xff0c;会弹出CMD窗口&#xff0c;出现qDebug的调试信息。 转载于:https://www.cnblogs.com/WindSun/p/10328404.html

WebAPIs移动端特效——不看你就亏大了

Web APIs 本篇学习目标: ✨能够写出移动端触屏事件 ✨能够写出常见的移动端特效 ✨能够使用移动端开发插件开发移动端特效 ✨能够使用移动端开发框架开发移动端特效 ✨能够写出 sessionStorage 数据的存储以及获取 ✨能够写出 localStorage 数据的存储以及获取 ✨能够说出它们两…

MVC是一种用于表示层设计的复合设计模式

它们之间的交互有以下几种&#xff1a;1.当用户在视图上做任何需要调用模型的操作时&#xff0c;它的请求将被控制器截获。2.控制器按照自身指定的策略&#xff0c;将用户行为翻译成模型操作&#xff0c;调用模型相应逻辑实现。3.控制器可能会在接到视图操作时&#xff0c;指定…

Centos7.2源码安装redis

1、下载redis包&#xff08;此处可到官网查看&#xff0c;有相应的命令&#xff09; wget http://download.redis.io/releases/redis-5.0.3.tar.gz 2、解压之后&#xff0c;并进行make编译 tar xzf redis-5.0.3.tar.gz -C /usr/local/cd /usr/local/redis-5.0.3/make如果出现如…

手撸移动端轮播图(内含源码)

移动轮播图 移动端轮播图与PC段轮播图&#xff0c;在技术选择上是有区别的&#xff0c;因为移动端的浏览器版本非常好&#xff0c;对于H5和CSS3的支持非常完美&#xff0c;所以很多效果可以CSS3的方式实现&#xff0c;比如可以使用 Transorm 属性替代原来的动画函数 可以自动…

原创jquery插件treeTable(转)

由于工作需要&#xff0c;要直观的看到某个业务是由那些子业务引起的异常&#xff0c;所以我需要用树表的方式来展现各个层次的数据。 需求&#xff1a; 1、数据层次分明&#xff1b; 2、数据读取慢、需要动态加载孩子节点&#xff1b; 3、支持默认展开多少层。 在网上找到了很…

初探Vue3

&#x1f31c;本篇文章目录\textcolor{green}{本篇文章目录}本篇文章目录 &#x1f31b; &#x1f435; 新构建工具Vite\textcolor{blue}{新构建工具Vite}新构建工具Vite &#x1f435; CompositionAPI火爆来袭\textcolor{blue}{Composition API火爆来袭}CompositionAPI火爆来…

linux执行python命令后permission denied

linux下执行python后显示被拒绝问题定位&#xff1a; 1、检查下要执行的文件的权限是否存在执行权限&#xff0c;否则执行chmod命令赋予权限&#xff1b; 2、若赋予权限后仍然显示没有权限&#xff0c;检查下执行的python文件是否有权限&#xff0c;否则执行chmod赋予执行权限。…

mysql zip 安装

第一步下载mysql.zip https://dev.mysql.com/downloads/mysql/5.7.html#downloads 第二步&#xff1a;解压文件后在其目录下&#xff0c; 新建 my.ini 注意编码为ansi&#xff0c;新建 data 空文件夹 my.ini内容为&#xff1a; [mysql]# 设置mysql客户端默认字符集default…

Vue3的响应式原理解析

Vue3的响应式原理解析 Vue2响应式原理回顾 // 1.对象响应化&#xff1a;遍历每个key&#xff0c;定义getter、setter // 2.数组响应化&#xff1a;覆盖数组原型方法&#xff0c;额外增加通知逻辑 const originalProto Array.prototype const arrayProto Object.create(orig…