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.pswp.cn/news/248585.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/248585.shtml
英文地址,請注明出處:http://en.pswp.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…