在 JavaScriptCore 中使用 NSBlock 作为 属性

Use a NSBlock as a property in JavaScriptCore

我需要使用 NSBlock 作为 属性,可以在 JavaScript 中更改。

@protocol ExportingUser <NSObject, JSExport>

@property (nonatomic, copy) void (^changedName) (void);

@property (nonatomic) NSString* name;

@end

我基本上想从 Obj-C 调用 changedName,一个定义来自 JavaScript 的函数。像这样:

user.name = "Peyman"; // this will change the name property in the Obj-C as well.

user.changedName = function() { console.log("yay"); } // but this doesn't

我知道这可以通过 JSValue 的 callWithArguments 方法实现,但如果可能的话我更喜欢这种方法。

编辑: 实际上,我认为 callWithArguments 方法行不通。这是可能的,因为绑定到 Objective-C 类 的对象在 JavaScript 中不可扩展,因此引入新字段将被忽略。

如JSValue.h所列:

//   Objective-C type  |   JavaScript type
// --------------------+---------------------
//         nil         |     undefined
//        NSNull       |        null
//       NSString      |       string
//       NSNumber      |   number, boolean
//     NSDictionary    |   Object object
//       NSArray       |    Array object
//        NSDate       |     Date object
//       NSBlock *     |   Function object *
//          id **      |   Wrapper object **
//        Class ***    | Constructor object ***
//
// * Instances of NSBlock with supported arguments types will be presented to
// JavaScript as a callable Function object. For more information on supported
// argument types see JSExport.h. If a JavaScript Function originating from an
// Objective-C block is converted back to an Objective-C object the block will
// be returned. All other JavaScript functions will be converted in the same
// manner as a JavaScript object of type Object.

显然,您可以逃脱:

@property (nonatomic, copy) JSValue* changedName;

然后,当你想调用它时:

typedef void (^nameChangedBlock)(void);

nameChangedObject = [self.changedName toObject];

if ([nameChangedObject isKindOfClass: NSClassFromString(@"NSBlock")]){
   ((nameChangedBlock)nameChangedObject)();
}