iOS React Native 學習總結

1、簡單介紹

不一樣於Hybrid ap,React Native裏面沒有webview,iOS7中加入了JavaScriptCore.framework框架,而RN正是用JavascriptCore執行js代碼的。html

2、環境配置

須要安裝Watchman Flow Node環境,推薦使用Homebrew,注意Xcode版本不能低於7.0java

  • brew install node Node安裝
  • brew install watchman
  • brew install flow
  • brew update && brew upgrade 環境更新

3、工程建立

國內須要換源node

1 npm config set registry https://registry.npm.taobao.org
2 npm config set disturl https://npm.taobao.org/dist

 

執行如下兩條命令安裝全局npm環境和初始化工程RNDEMOreact

$ sudo npm install -g react-native-cli
$ react-native init RNDemo

 

cd到工程根目錄中用npm start(若是開啓了自動啓動調試服務器則不須要)啓動服務,而後運行工程web

集成RN環境到Native中

1.拷貝node_modules環境到工程中npm

2.將須要的.xcodeproj文件添加到工程中react-native

3.點擊 項目>Targets>Bulid Phases>Link Binary With Libraries添加對應的靜態庫數組

4.點擊 項目>Targets>Bulid Settings>Search Paths>Header Search Paths註冊React.xcodeproj文件路徑xcode

5.由於靜態庫裏面可能有Category 因此須要在項目>Targets>Build Settings -> other linker flags 中加入-ObjC或者-all_load服務器

4、RN在工程用的一些應用

關於原生組件

  RN能用JS方便地調用官方封裝的組件來加大開發效率,可是一些個性化或者js不太方便的東西仍是須要native實現,因而須要native提供一些原生組件來完善。這主要分爲兩類,Module類和View類

  1. Module類須要導入頭文件#import "RCTBridgeModule.h"並遵照RCTBridgeModule協議
  2. ViewManager類須要導入頭文件#import "RCTViewManager.h"並繼承至RCTViewManager,遵照RCTBridgeModule協議並實現- (UIView *)view方法return view;即爲自定義組件。

  兩種類都須要實現 RCT_EXPORT_MODULE(js_name) 協議宏,js_name是js調用該類名稱,缺省狀況下截取類所在文件名,一個類所在文件被引用時,系統會調用其+(void)load函數,當RCT_EXPORT_MODULE()所在文件被引用時,系統調用load 函數,函數裏簡單的調用RCTRegisterModule(self) 把本身註冊到一個全局數組RCTModuleClasses,這樣系統中導出的類都會自動註冊到這個全局變量數組裏

void RCTRegisterModule(Class moduleClass)
{
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        RCTModuleClasses = [NSMutableArray new];
    });

    RCTAssert([moduleClass conformsToProtocol:@protocol(RCTBridgeModule)], @"%@ does not conform to the RCTBridgeModule protocol", moduleClass);

    // Register module
    [RCTModuleClasses addObject:moduleClass];
}

 

屬性導出

  RN能夠向Native傳遞多種參數,能夠以這些支持的類型傳遞數據native組件用EXPORT_VIEW_PROPERTY(<#name#>, <#type#>)來導出類的屬性,js傳遞數據會調用相應的set方法,native能夠在set方法裏面作些邏輯和數據處理。支持字符串NSString,NSArray數組,基本數據類型,NSnumeber,NSDictionary字典等,自定義類型,並在RCTCovert中,重定義了以下幾種數據類型來處理一些泛型

typedef NSArray NSArrayArray __deprecated_msg("Use NSArray");
typedef NSArray NSStringArray __deprecated_msg("Use NSArray");
typedef NSArray NSStringArrayArray __deprecated_msg("Use NSArray<NSArray *>");
typedef NSArray NSDictionaryArray __deprecated_msg("Use NSArray");
typedef NSArray NSURLArray __deprecated_msg("Use NSArray");
typedef NSArray RCTFileURLArray __deprecated_msg("Use NSArray");
typedef NSArray NSNumberArray __deprecated_msg("Use NSArray");
typedef NSArray UIColorArray __deprecated_msg("Use NSArray");

 

  枚舉類型用RCT_ENUM_CONVERTER(type, values, default, getter)導出 例如:

RCT_ENUM_CONVERTER(UIActivityIndicatorViewStyle, (@{
@"large": @(UIActivityIndicatorViewStyleWhiteLarge),
@"small": @(UIActivityIndicatorViewStyleWhite),
}), UIActivityIndicatorViewStyleWhiteLarge, integerValue)

 

  values爲字典類型,default在js傳遞數據爲空時候使用         
方法導出

  RCT_EXPORT_METHOD(<#method#>)可導出方法,js經過註冊到全局數組RCTModuleClasses中的實例來調用方法

RCT_EXPORT_METHOD(getCurrentVersion:(RCTResponseSenderBlock)callback)
{

    NSString *events = [self appVersion];
    callback(@[events]);

}

 

  
Nativ模塊實現

  React Native 在一個單獨的串行 GCD 隊列中調用 native 模塊方法,若是 native 模塊須要調用 main-thread-only iOS API例如刷新UI,push viewController 應該在主隊列操做:

-(void)whatYouWantTodo{
  dispatch_async(dispatch_get_main_queue(), ^{
    coding......
  }
}

 

Block回調

  對應屬性導出,native也能夠向js傳遞數據,RCTBridgeMethod中定義了一個block typedef void (^RCTResponseSenderBlock)(NSArray *response);用來返回數據給js。   

發送事件到 JavaScript

RCTEventDispatcher類中定義了一些事件處理方法

例如Native 模塊能夠在不被直接調用的狀況下向 JavaScript 發送事件信號

- (void)calendarEventReminderReceived:(NSNotification *)notification
{
    NSString *eventName = notification.userInfo[@"name"];
    [self.bridge.eventDispatcher sendAppEventWithName:@"EventReminder"
                                           body:@{@"name": eventName}];
}
@end

 

JavaScript 代碼能夠訂閱這些事件:

var subscription = DeviceEventEmitter.addListener(

    'EventReminder',
    (reminder) => console.log(reminder.name)
);

 

tips:js須要移除訂閱事件

subscription.remove();

 

5、簡單提提JavaScriptCore

OC調用js
-(void)webViewDidFinishLoad:(UIWebView *)webView  
{  
    //網頁加載完成調用此方法     
    //首先建立JSContext 對象(此處經過當前webView的鍵獲取到jscontext)  
    JSContext *context=[webView valueForKeyPath: @"documentView.webView.mainFrame.javaScriptContext"];  
    NSString *alertJS=@"alert('超哥你好,大河向東流')"; //準備執行的js代碼  
    [context evaluateScript:alertJS];//經過oc方法調用js的alert
}

 

  效果以下: 

block中JSContext注意防止循環引用,

  用[JSContext currentContext]

  JSContext *context1 = [[JSContext alloc] init];
context1[@"callback"] = ^{
    JSValue *object = [JSValue valueWithNewObjectInContext:[JSContext currentContext]];
    object[@"one"] = @(1);
    object[@"two"] = @(2);
    return object;
};

 

JSValue內存泄漏

  JS中對象爲弱類型,OC中爲強類型直接保存會內存泄漏

- (void)setOnClickHandler:(JSValue *)handler
{
    _onClickHandler = [JSManagedValue managedValueWithValue:handler];
    [_context.virtualMachine addManagedReference:_onClickHandler
                                    withOwner:self]
}

 

資料參考:
  1. JavaScriptCore的使用和消息傳遞
  2. JavaScriptCore與內存管理
  3. React Native官方文檔中文
  4. 通信以及消息循環

知識淺薄,若有錯漏請指正。

相關文章
相關標籤/搜索