IOS7開發~JavaScriptCore (一)

IOS7開發~JavaScriptCore(一)

http://blog.csdn.net/zfpp25_/article/details/9232129

IOS7開發~JavaScriptCore(二)

http://blog.csdn.net/zfpp25_/article/details/9236357



IOS7之前,接觸 JS 更多的是處理UIWebView的時候,如:http://blog.csdn.net/zfpp25_/article/details/8650412

但IOS7引入了JS框架<JavaScriptCore/JavaScriptCore.h>,給了“純IOS程序員”一個枯木逢春的契機~學習強大的 JavaScript。



1、 基本概念


JavaScriptCore.framework :iOS7 中新加入的框架,用來處理JavaScript。JavaScriptCore 是蘋果 Safari 瀏覽器的 JavaScript 引擎,JavaScriptCor在 OS X 平臺上很早就存在的,而在 iOS 平臺,直到IOS7纔對外開放,並提供了 Objective-C 的接口


2、主要內容

Objective-C → JavaScript
• JavaScript → Objective-C 

• Memory management
• Threading
• JavaScriptCore C API
• JavaScriptCore with a WebView


首先引入框架   #import <JavaScriptCore/JavaScriptCore.h>


一、Objective-C → JavaScript

瞭解下面幾個類:

JSContext:An instance of JSContext represents a JavaScript execution environment.(一個 Context 就是一個 JavaScript 代碼執行的環境,也叫作用域。

JSValue:Conversion between Objective-C and JavaScript types.(JS是弱類型的,ObjectiveC是強類型的,JSValue被引入處理這種類型差異,在 Objective-C 對象和 JavaScript 對象之間起轉換作用

Objective-C 和 JavaScript 中類型的對照表:



實例代碼:1

int main() {
    JSContext *context = [[JSContextalloc]init];
    JSValue *result = [context evaluateScript:@"2 + 2"];
    NSLog(@"2 + 2 = %d", [result toInt32]);
    return 0;
}

實例代碼:2

(1)新建一個test.js文件,其中實現代碼:

//計算階乘
var factorial = function(n) {
    if (n < 0)
        return;
    if (n === 0)
        return 1;
    return n * factorial(n - 1)
};



(2)調用時實現代碼:

- (void) factorial
    {
        NSString *path = [[NSBundlemainBundle]pathForResource:@"test"ofType:@"js"];
        NSString *testScript = [NSStringstringWithContentsOfFile:pathencoding:NSUTF8StringEncodingerror:nil];
        
        JSContext *context = [[JSContextalloc]init];
        [context evaluateScript:testScript];
        
        JSValue *function = context[@"factorial"];
        JSValue *result = [function callWithArguments:@[@10]];
        NSLog(@"factorial(10) = %d", [resulttoInt32]);
    }

這樣就計算出了10的階乘。


注意:如果運行結果不正確,注意js文件是否已經加到項目的Buddle Resources中




二、JavaScript → Objective-C


• Two ways to interact with Objective-C from JavaScript (可以通過兩種方式在 JavaScript 中調用 Objective-C

Blocks :JS functions (對應 JS 函數
JSExport protocol :JS objects (對應 JS 對象


(1)Blocks

- (void) testMakeUIColor
    {
        JSContext *context = [[JSContextalloc]init];
        
        context[@"creatUIColor"] = ^(NSDictionary *rgbColor){
            return [UIColor colorWithRed:([rgbColor[@"red"] floatValue] /255.0)
                                   green:([rgbColor[@"green"]floatValue] /255.0)
                                    blue:([rgbColor[@"blue"]floatValue] /255.0)
                                   alpha:1];
        };
        JSValue *color = [contextevaluateScript:@"makeUIColor({red: 150, green: 150, blue: 200})"];
        NSLog(@"color:%@",[colortoObject]);
    }

注意:

1、Avoid capturing JSValues,  Prefer passing as arguments.(不要在 Block 中直接使用外面的 JSValue 對象, 把 JSValue 當做參數來傳進 Block 中。)

2、Avoid capturing JSContexts, Use + [JSContext currentContext] (避免循引用,不要在 Block 中直接引用使用外面的 JSContext 對象,應該用[JSContext currentContext];)

錯誤的做法:



正確的做法:



(2)JSExport protocol

首先引入 

#import <objc/runtime.h>

實例代碼1:    JS代碼設置Button 的 title

@protocol UIButtonExport <JSExport>
- (void)setTitle:(NSString *)title forState:(UIControlState)state;
@end
- (void) test
{
    class_addProtocol([UIButtonclass],@protocol(UIButtonExport));
    
UIButton *button = [UIButtonbuttonWithType:UIButtonTypeSystem];
    [button setTitle:@"Hello Objective-C"forState:UIControlStateNormal];
    button.frame = CGRectMake(20,40,280,40);

    JSContext *context = [[JSContextalloc]init];
context[@"button"] = button;
[context evaluateScript:@"button.setTitleForState('Hello JavaScript', 0)"];
    
    [self.view addSubview:button];
}


說明:

上面代碼中,我們申明一個 UIButtonExport 協議,該協議繼承於 JSExport,並將setTitle:forState:方法開放到該協議中(只有 JSExport 協議中的方法才能被 JavaScript 識別),然後通過運行時讓 UIButton 遵循 UIButtonExport 協議。這樣你就可以在 JS 中爲 Button 設置 title 了,需要說明一點的是,在 JS 中方法的命名規則與 Objective-C 中有點不一樣,如 Objective-C 中的方法-(void)setX:(id)x Y:(id)y Z:(id)z;,加入到 JSExport 協議中,在 JS 中調用就得是setXYZ(x, y, z);,當然如果你不想根據這種命名轉換規則,你也可以通過 JSExport.h 中的方法來修改:


#define JSExportAs(PropertyName, Selector) \
    @optional Selector __JS_EXPORT_AS__##PropertyName:(id)argument; @required Selector
#endif

如 setX:Y:Z 方法,我們可以給他重命名,讓 JS 中通過 set3D(x,y,z) 來調用

JSExportAs(set3D,
     - (void)setX:(id)x Y:(id)y Z:(id)z
);

實例代碼2:

a、新建類 NativeObject,代碼實現L:

.h代碼:

#import <Foundation/Foundation.h>
@import JavaScriptCore;
@protocol NativeObjectExport <JSExport>
-(void)log:(NSString*)string;
@end

@interface NativeObject : NSObject <NativeObjectExport>
@end

.m代碼:
#import "NativeObject.h"
@implementation NativeObject

-(void)log:(NSString*)string {
    NSLog(@"js: %@", string);
}
@end

調用代碼:
- (void) testLog
{
    JSContext *context = [[JSContextalloc]init];
    context[@"nativeObject"] = [[NativeObjectalloc]init];
    [context evaluateScript:@"nativeObject.log(\"Hello Javascript\")"];
}


其它:

IOS7開發~JavaScriptCore (二)


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章