【问题标题】:ObjectiveC and JavaScriptCore: Will using this method of calling CallBacks cause memory issues?ObjectiveC 和 JavaScriptCore:使用这种调用 CallBacks 的方法会导致内存问题吗?
【发布时间】:2014-01-15 20:33:19
【问题描述】:

免责声明:这是一篇很长的帖子,但对于那些努力使用新的 ObjectiveC JavascriptCore 框架并在 ObjC 和 JS 之间进行异步编码的人来说可能非常有价值。

您好,我是 Objective C 的超级新手,我正在将一个 javascript 通信库集成到我的 iOS 应用程序中。

无论如何,我一直在尝试使用 iOS7 中引入的新的 ObjectiveC JavaScriptCore 框架。在大多数情况下,它都非常棒,尽管到目前为止记录得很少。

混合语言惯例真的很奇怪,但在某些方面也是一种解放。

我应该补充一点,我当然在使用 ARC,所以这对 Javascript 世界有很大帮助。但是在 ObjectiveC 和 JSContext 回调之间移动时,我有一个关于内存使用问题的非常具体的问题。就像我在 Javascript 中执行一个函数,然后执行一些异步代码,然后回调到定义的 ObjectiveC 块,然后调用定义的 JS 回调......我只是想确保我做对了(即. 不会在某个地方泄漏内存)!

只是为了做正确的事情(因为我引用了一个类 self 来调用 ObjectiveC 回调我创建了一个 weakSelf 所以它与 ARC 配合得很好(引用自问题:capturing self strongly in this block is likely to lead to a retain cycle):

__unsafe_unretained typeof(self) weakSelf = self;

现在,假设我有一个 JSContext 并向它添加一个函数。我希望这个函数采用一个回调函数并使用“Hello”作为参数调用它以及将另一个函数作为回调传递。即。

// Add a new JSContext.
JSContext context = [[JSContext alloc] initWithVirtualMachine:[[JSVirtualMachine alloc] init]];

// Add a function to the context. This function takes a callBack function and calls it back with "Hello"
[context evaluateScript: @"var functionA = function(callBack){
      var aMessage = "Foo";
      callBack(aMessage, function(message){
            /* message should say: Foo Bar */
      });
}" ];
// Note, if you try to copy this code, you will have to get rid of the returns in the JS script.

好的,所以我们有了基本的 JS 方面。现在添加 ObjectiveC 的复杂性。我要添加第一个 ObjectiveC CallBack 块:

context[@"functionB"] = ^(NSString *theMessage, JSValue *theCallBack){
    [weakSelf objCFunction:theMessage withCallBack:theCallBack];
};

在同一个类中,这一切都发生在我也有方法定义。 这是我最担心的地方

-(void)objCFunction:(NSString *)message withCallBack:(JSValue *)callBack
{
    NSString *concatenatedString = [NSString stringWithFormat:@"%@%@", message, @"Bar"];
    [callBack callWithArguments:@[concatenatedString]];
}

所以当我打电话时:

[context evaluateScript: @"functionA(functionB);" ];

它应该通过链条,它完全符合我的预期。

我主要担心的是我希望我不会以某种方式在这条链上的某个地方捕获一个 JSValue,然后泄漏出去。

任何帮助我理解 ARC/JSMachine 将如何管理这种在 Objective C 和 Javascript 之间流畅地调用回调的方法,将非常有价值!

另外,我希望这个问题可以帮助其他正在尝试这个框架的人。

谢谢!

【问题讨论】:

    标签: objective-c ios7 automatic-ref-counting objective-c-blocks javascriptcore


    【解决方案1】:

    当您有两个对象,每个对象都保留另一个对象的一部分时,就会出现保留循环的问题。它不是特定于 JavascriptCore。它甚至不是特定于块的,尽管块使问题更容易出错。

    例如

    @interface ObjcClass : NSObject
    @property (strong,nonatomic) JSValue *badProp;
    
    
    - (void) makeEvilRetainWithContext:(JSContext *) context;
    @end
    
    - (void) makeEvilRetainWithContext:(JSContext *) context{
      context[@"aFunc"]=^(JSValue *jsValue){
        self.badProp=jsValue;
      };
    }
    

    self.context[@"aFunc"] 现在保留了 ObjcClass 对象,因为 self.badProp 现在位于函数 obj 中,该函数位于通过将块分配给 @"aFunc" 所创建的上下文中。同样,保留上下文是因为它自己的强保留值之一保留在 self.badProp 中。

    真的,避免这一切的最好方法就是永远不要尝试将 JSValue 存储在 Objective-c 对象中。似乎真的没有必要这样做,例如

    @property (strong,nonatomic) NSString *goodProp;
    
    
    - (void) makeGoodFunc:(JSContext *) context;
    @end
    
    - (void) makeGoodFunc:(JSContext *) context{
      context[@"aFunc"]=^(JSValue *jsValue){
        self.goodProp=[JSValue toString];
      };
    }
    

    您的代码不是问题,因为简单地通过方法传递 JSValue(甚至是函数)不会保留它。

    另一种思考方式可能是:objCFunction:withCallBack: 执行后,self 所代表的对象是否仍然可以访问作为callBack 传递的 JSValue?如果不是,则没有保留周期。

    【讨论】:

    • 很好的解释。谢谢!
    • 在使用了几个月的 Objective C 之后现在来看它似乎很明显。但是你的回答在很多层面上都非常彻底和信息丰富。
    【解决方案2】:

    查看 Apple 开发者网络上的 WWDC 介绍“将 JavaScript 集成到本机应用程序”会话:https://developer.apple.com/wwdc/videos/?id=615 - 它包含关于块和避免捕获 JSValue 和 JSContext 的部分

    在您上面的示例代码中,所有 JSValue 都作为参数传递(Apple 推荐的方式),因此引用仅在代码执行时存在(不捕获 JSValue 对象)。

    【讨论】:

      猜你喜欢
      • 2023-03-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多