接觸JSPatch也快一年,在此總結歸納一些新接觸的開發者容易碰到的一些問題。其實很多問題bang哥在wiki中已經寫的很詳細了,建議花點時間仔細看看下面這兩個WiKi內容。
想要了解JSPatch實現原理可以先看 JSPatch 實現原理詳解
require匯入類
只需要一對' '
, 多個類之間用逗號 ,
分隔:
require('UIView, UIColor')
複製程式碼
方法遇到下劃線_
需要特別注意
因為JSPatch是通過_
來分割方法引數的,所以遇到方法本身帶有_
的時候需要使用__
雙下劃線代替,否則會被識別成一個引數,導致出現類似如下的報錯。
//OC方法程式碼如下
- (BOOL)_test_Bool {
NSLog(@"我是oc testBool");
return NO;
}
//JS錯誤呼叫程式碼如下
var testBool = self._test_Bool();
複製程式碼
我們知道selector 的 一個:
代表有一個引數,結合報錯資訊可知runtime所找的方法是帶兩個引數的,所以肯定跟你需要呼叫的方法不一致,找不到則會導致崩潰。
把JS呼叫程式碼改為下面這種即可,每個下劃線_
變成雙_
,同理如果你方法中本身是雙下劃線__
則需要變成____
四個下劃線。
//JS正確呼叫程式碼如下
var testBool = self.__test__Bool();
複製程式碼
如果需要替換的方法本身帶有下劃線,與方法呼叫相同,也同樣需要雙下劃線__
__test__Bool:function(){
console.log("我是js testBool");
return YES;
}
複製程式碼
undefined is not an object(evaluating 'self.__c')
提示意思是self這個物件不存在,結合JSPatch的使用場景可以推測出這個錯誤一般是由於在block中使用self引起的,解決辦法參考block 裡使用 self 變數。但值得注意的是,在JS中,如果報了類似的undefined is not an object aaa.bbb錯誤,則是因為aaa這個物件為undefined,而你又要訪問一個undefined的物件屬性或者方法在JS中會導致崩潰。
####一個最簡單高效獲取物件類名方法
大多數需求場景下可以通過object.__clsName
的方式獲取OC物件類名。不需要通過isKindOfClass或者NSStringFromClass(此方法需要預先新增C函式擴充套件)來獲取,而且不需要與OC相互通訊。
//替換按鈕點選方法
handleBtn: function(sender) {
var btnClassName = sender.__clsName;
console.log("btnClassName is : " + btnClassName);
}
複製程式碼
下面列舉一些有__clsName
屬性的OC物件情況。
- JSPatch 通過hook訊息轉發forwardInvocation: 方法,在呼叫替換方法或者新新增的方法時給引數新增了
__clsName
標記來儲存類名(所以類似圖一的sender引數就會有__clsName屬性),但是Class、NSNumber、BOOL、CGFloat、結構體不知道還有沒有o(╯□╰)o,感興趣的可以去檢視原始碼
除外。 - 通過 require 引入的類,所以在JS內通過init出來的物件都會有
__clsName
屬性。 - 屬性和私有變數值和方法返回值(Class、NSNumber、BOOL、CGFloat、結構體
不知道還有沒有o(╯□╰)o感興趣的可以去檢視原始碼
除外,不過這些好像需要知道類名情況比較少) - 歡迎補充
####OC物件和JS物件
大家在JSPatch交流群裡所說的OC物件指的是從OC中獲取的JS物件如var str = self.str()
或 通過JS初始化的物件var str = NSString.stringWithFormat("Hello World")
,而JS物件指的是例如 var str = "我是js物件"
或var str = self.str().toJS()
之後的JS物件。OC物件應該使用OC中相應方法,JS物件應該使用JS中相應方法。
//替換按鈕點選方法
handleBtn: function(sender) {
var btnClassName = sender.__clsName;
console.log("btnClassName is : " + btnClassName);
//初始化的OC物件
var ocInitStr = NSString.stringWithFormat("Hello World")
//獲取屬性得到的OC物件
var str = self.str();
console.log("ocInitStr 擷取前5個字元:" + ocInitStr.substringToIndex(5).toJS())
//JS物件
var jsStr = "我是JS物件";
console.log("jsStr 擷取前4個字元:" + jsStr.substr(0,4))
}
複製程式碼
####JS中如何使用強轉
答:不需要強轉,直接當成強轉之後的型別使用,JS裡面沒有型別的概念,都是物件。
####列舉
直接使用值
Note:可在Xcode用NSLog列印檢視具體值
####Block還未被賦值就被呼叫的問題 js exception, msg: block is not a function. (In 'block(xxx,...., xxx)', 'block' is false) 類似的報錯通常是因為你獲取的block還沒有被賦值,所以在js中沒有正確的執行,解決辦法是獲取到block之後,判斷是否存在:
//示例方法
xxxfunction: function(sender) {
var block = self.testBlock();
if(block){//加上這個判斷
//do something with block
block(xxx,...,xxx);
}
}
複製程式碼