JavaScriptCore的巨坑(JSExportAs方式綁定的本地通信)

前言

本篇分享的類(lèi)型不是學(xué)習(xí)教程鳍侣,并且要有一點(diǎn)JavaScriptCore基礎(chǔ)禁筏。

畢竟這一塊網(wǎng)上一大堆的學(xué)習(xí)教程尽楔,博主就沒(méi)必要班門(mén)弄斧了投储。

本篇的目的是分享JavaScriptCore中用JSExport協(xié)議和JSExportAs宏來(lái)進(jìn)行jsoc通信的兩個(gè)大坑。
<ol>
<li>內(nèi)存泄露</li>
<li>調(diào)用-[JSValue callWithArguments]野指針問(wèn)題</li>
</ol>

block方式來(lái)進(jìn)行js和oc的通信沒(méi)這兩個(gè)大坑阔馋。

第一個(gè)坑:內(nèi)存泄露

一般綁定JSContext里的native的寫(xiě)法都是self.context[@"native"] = self玛荞。但是這樣寫(xiě)會(huì)產(chǎn)生內(nèi)存泄露(泄露原理就是互相持有了),這個(gè)坑隨便百度Google一下也能找到很多解決方案呕寝。目前博主的解決方案是native指定一個(gè)新的對(duì)象勋眯,然后在指定對(duì)象里實(shí)現(xiàn)JSExport協(xié)議。
貼上博主在項(xiàng)目里用到的核心代碼 :

和js通信的控制器頁(yè)面核心代碼

// 以 JSExport 協(xié)議關(guān)聯(lián) native 的方法
self.context[@"native"] = [[NMFormFlowWapNativeManager alloc] initWithDelegate:self];

NMFormFlowWapNativeManager.h

@interface NMFormFlowWapNativeManager : NSObject

- (instancetype)initWithDelegate:(id<NMFormFlowWapNativeManagerDelegate>)delegate;

@property (nonatomic,weak) id<NMFormFlowWapNativeManagerDelegate> delegate;

@end

NMFormFlowWapNativeManager.m

@import JavaScriptCore;

@protocol TestJSExport <JSExport>

JSExportAs(nativeCall, - (void)nativeCallHandleWithType:(NSString *)nativeType parameter:(NSString *)parameter jsType:(NSString *)jstype);

@end

@interface NMFormFlowWapNativeManager () <TestJSExport>

@end

@implementation NMFormFlowWapNativeManager

- (instancetype)initWithDelegate:(id<NMFormFlowWapNativeManagerDelegate>)delegate {
    if (self = [super init]) {
        self.delegate = delegate;
    }
    return self;
}

- (void)nativeCallHandleWithType:(NSString *)nativeType parameter:(NSString *)parameter jsType:(NSString *)jsType {
    NSDictionary *dicParams = [NSJSONSerialization JSONObjectWithData:[parameter dataUsingEncoding:NSUTF8StringEncoding] options:NSJSONReadingMutableLeaves error:nil];
    [self.delegate nativeCallHandleWithThread:webThread type:nativeType parameter:dicParams jsType:jsType];
}

PS:代碼并不是完整的,但最核心的關(guān)鍵已經(jīng)貼上來(lái)了客蹋。順便簡(jiǎn)單解釋一下塞蹭。由于native管理的對(duì)象交給了另一個(gè),所以在管理者對(duì)象里新開(kāi)了一個(gè)代理回調(diào)讶坯。方便在控制器那邊接收得到JS的事件番电。只要有點(diǎn)基礎(chǔ)的,一看就懂了辆琅。畢竟本篇不是學(xué)習(xí)教程漱办,而是分享坑的。

第二個(gè)坑:-[JSValue callWithArguments]野指針問(wèn)題

這個(gè)問(wèn)題有點(diǎn)奇葩婉烟,JSValue的callWithArguments就是oc調(diào)用js函數(shù)所執(zhí)行的方法娩井。那這簡(jiǎn)單的函數(shù)怎么發(fā)生野指針問(wèn)題尼。
那就是oc進(jìn)行網(wǎng)絡(luò)請(qǐng)求似袁,請(qǐng)求完回調(diào)的時(shí)候調(diào)用JSValue的callWithArguments的方法就是產(chǎn)生野指針洞辣,而且是間接性的,有時(shí)候會(huì)有時(shí)候不會(huì)昙衅。一旦崩潰基本都直接飛去main函數(shù)了扬霜。。绒尊。畜挥。

這個(gè)問(wèn)題百度Google都找了許久也沒(méi)找到類(lèi)似的問(wèn)題和解決方案。只是崩潰的時(shí)候婴谱,左邊的堆棧提示webThread(當(dāng)時(shí)猜測(cè)可能是線(xiàn)程間通信影響的此問(wèn)題)蟹但,然后我蒙一下切換到webView的線(xiàn)程里去調(diào)用callWithArguments函數(shù)試試,結(jié)果就從未發(fā)生過(guò)崩潰了谭羔。

例子:

假設(shè)华糖,h5上有一個(gè)圖片顯示和一個(gè)button,點(diǎn)擊button的時(shí)候瘟裸,調(diào)用本地?cái)z像頭并且上傳圖片到服務(wù)器客叉,上傳完之后在調(diào)用js一個(gè)函數(shù),告訴js圖片上傳成功话告,讓js去做對(duì)應(yīng)的邏輯兼搏。這個(gè)時(shí)候網(wǎng)絡(luò)請(qǐng)求完回調(diào)里的線(xiàn)程是主線(xiàn)程,調(diào)用callWithArguments的時(shí)候沙郭,就會(huì)間接性的崩潰佛呻。

解決方案

解決辦法就是回到webView的線(xiàn)程去調(diào)用callWithArguments就不會(huì)崩潰(因?yàn)閖s和oc綁定的函數(shù),在函數(shù)里執(zhí)行的代碼不是在主線(xiàn)程里執(zhí)行的)病线。
模擬代碼:

///假設(shè)這個(gè)函數(shù)是和js的test函數(shù)綁定的吓著。如果監(jiān)聽(tīng)到這個(gè)函數(shù)就進(jìn)行網(wǎng)絡(luò)請(qǐng)求或者上傳圖片等操作鲤嫡。
- (void)test {
  //獲取webView線(xiàn)程,因?yàn)閖s和oc綁定的函數(shù)里執(zhí)行的代碼不是在主線(xiàn)程里绑莺。
NSThread *webThread = [NSThread currentThread];
//網(wǎng)絡(luò)請(qǐng)求
@weakify(self);
[HTTPRequest requestGetTokenWithFinished:^(void){
  @strongify(self);

  //通知js請(qǐng)求完了暖眼。

 //正常情況下是直接在這里調(diào)用,但是會(huì)間接性發(fā)生野指針問(wèn)題纺裁,差不多每隔四五次發(fā)生一次野指針诫肠。
  //JSValue *jsCall = self.context[@"jsCall"];
  //[jsCall callWithArguments:nil];

  //線(xiàn)程安全的,用此方式对扶,筆者再也沒(méi)發(fā)生過(guò)野指針問(wèn)題区赵。
  [self performSelector:@selector(jsCall) onThread:webThread withObject:nil waitUntilDone:NO];
}];
}

- (void)jsCall {
  JSValue *jsCall = self.context[@"jsCall"];
  [jsCall callWithArguments:nil];
}

結(jié)語(yǔ)

總之筆者分享此文章的主要目的是第二個(gè)野指針問(wèn)題,因?yàn)楣P者在Google和stackoverflow里也找了很久也找不到問(wèn)題原因浪南,然后都是蒙對(duì)的,所以才來(lái)進(jìn)行分享漱受÷缭洌可能對(duì)于不懂JavaScriptCore看起來(lái)有點(diǎn)困難,總之可以先了解一下昂羡。而對(duì)于js和oc的通信的業(yè)務(wù)不復(fù)雜的或者使用block進(jìn)行通信的絮记,應(yīng)該很難遇到此問(wèn)題。再者虐先,網(wǎng)上很多學(xué)習(xí)教程基本都是推薦callWithArguments在主線(xiàn)程里調(diào)用怨愤,但目前筆者認(rèn)為應(yīng)該還是讓它在webView的線(xiàn)程里去執(zhí)行(那個(gè)野指針問(wèn)題就是在主線(xiàn)程里執(zhí)行所發(fā)生的)。

callWithArguments野指針問(wèn)題的底層實(shí)際發(fā)生原理也并不是很清楚蛹批。所以目前只能說(shuō)博主是怎么解決的撰洗,但是為什么.....博主也不知其然了。有知道的方便的話(huà)也可告知一下腐芍。

而對(duì)于demo.....筆者也想寫(xiě)差导,但對(duì)于html、js并不是很熟悉(頂多看得懂幾個(gè)標(biāo)簽)猪勇。所以....無(wú)能為力奉上demo了设褐。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市泣刹,隨后出現(xiàn)的幾起案子助析,更是在濱河造成了極大的恐慌,老刑警劉巖椅您,帶你破解...
    沈念sama閱讀 221,576評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件外冀,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡襟沮,警方通過(guò)查閱死者的電腦和手機(jī)锥惋,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,515評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門(mén)昌腰,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人膀跌,你說(shuō)我怎么就攤上這事遭商。” “怎么了捅伤?”我有些...
    開(kāi)封第一講書(shū)人閱讀 168,017評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵劫流,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我丛忆,道長(zhǎng)祠汇,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 59,626評(píng)論 1 296
  • 正文 為了忘掉前任熄诡,我火速辦了婚禮可很,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘凰浮。我一直安慰自己我抠,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,625評(píng)論 6 397
  • 文/花漫 我一把揭開(kāi)白布袜茧。 她就那樣靜靜地躺著菜拓,像睡著了一般。 火紅的嫁衣襯著肌膚如雪笛厦。 梳的紋絲不亂的頭發(fā)上纳鼎,一...
    開(kāi)封第一講書(shū)人閱讀 52,255評(píng)論 1 308
  • 那天,我揣著相機(jī)與錄音裳凸,去河邊找鬼贱鄙。 笑死,一個(gè)胖子當(dāng)著我的面吹牛登舞,可吹牛的內(nèi)容都是我干的贰逾。 我是一名探鬼主播,決...
    沈念sama閱讀 40,825評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼菠秒,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼疙剑!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起践叠,我...
    開(kāi)封第一講書(shū)人閱讀 39,729評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤言缤,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后禁灼,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體管挟,經(jīng)...
    沈念sama閱讀 46,271評(píng)論 1 320
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,363評(píng)論 3 340
  • 正文 我和宋清朗相戀三年弄捕,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了僻孝。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片导帝。...
    茶點(diǎn)故事閱讀 40,498評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖穿铆,靈堂內(nèi)的尸體忽然破棺而出您单,到底是詐尸還是另有隱情,我是刑警寧澤荞雏,帶...
    沈念sama閱讀 36,183評(píng)論 5 350
  • 正文 年R本政府宣布虐秦,位于F島的核電站,受9級(jí)特大地震影響凤优,放射性物質(zhì)發(fā)生泄漏悦陋。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,867評(píng)論 3 333
  • 文/蒙蒙 一筑辨、第九天 我趴在偏房一處隱蔽的房頂上張望俺驶。 院中可真熱鬧,春花似錦棍辕、人聲如沸痒钝。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,338評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至蚕甥,卻和暖如春哪替,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背菇怀。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,458評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工凭舶, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人爱沟。 一個(gè)月前我還...
    沈念sama閱讀 48,906評(píng)論 3 376
  • 正文 我出身青樓帅霜,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親呼伸。 傳聞我的和親對(duì)象是個(gè)殘疾皇子身冀,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,507評(píng)論 2 359

推薦閱讀更多精彩內(nèi)容

  • 本文由我們團(tuán)隊(duì)的 糾結(jié)倫 童鞋撰寫(xiě)。 寫(xiě)在前面 本篇文章是對(duì)我一次組內(nèi)分享的整理括享,大部分圖片都是直接從keynot...
    知識(shí)小集閱讀 15,255評(píng)論 11 172
  • 寫(xiě)在前面 本篇文章是對(duì)我一次組內(nèi)分享的整理搂根,大部分圖片都是直接從keynote上截圖下來(lái)的,本來(lái)有很多炫酷動(dòng)效的铃辖,...
    等開(kāi)會(huì)閱讀 14,469評(píng)論 6 69
  • 注:本文copy自http://www.reibang.com/p/ac534f508fb0剩愧,純屬當(dāng)筆記使用。 概...
    BookKeeping閱讀 732評(píng)論 1 3
  • 原創(chuàng)文章轉(zhuǎn)載請(qǐng)注明出處娇斩,謝謝 相信HotFix大家應(yīng)該都很熟悉了仁卷,今天主要對(duì)于最近調(diào)研的一些方案做一些總結(jié)穴翩。iOS...
    北辰明閱讀 7,677評(píng)論 6 60
  • 只需要清理SDWebImage的圖片緩存,直接用SDImageCache單例的getSize方法 2.除了圖片還有...
    lym不解釋閱讀 192評(píng)論 0 0