如何停止iOS中的JSContext评估?

问题描述 投票:1回答:2

我需要在运行时中断[context evaluateScript:js],在文档和Google中找不到方法。谁能帮忙?

ios objective-c javascriptcore
2个回答
1
投票

我无法通过JavaScriptCore使它正常工作。我尝试过:

  • 将代码包装在DispatchWorkItem中并调用cancel()
  • [将代码包装在Operation中并尝试取消它,以及nilOperationQueue进行编码(这实际上会导致应用程序崩溃)。
  • 使用JavaScriptCore中的C API以及-fno-objc-arc标志来手动管理内存。

没有这些工作。

什么完成工作使用WKWebView,并且一旦使用nilevaluateJavaScript函数就会调用其完成处理程序。我发布了一个示例here

对于任何尝试这样做的人,请记住,这是未记录的行为,因此在以后的任何iOS版本中都可能会更改。


1
投票

如果使用JSContextevaluateJavaScript方法。由于上下文中没有取消方法,因此您无法停止它。 iOS不喜欢macOS可以使用XPC,因此无法停止外部运行环境。

但是,有一种解决方法。只是认为JSContext喜欢浏览器。脚本在进行中。如何通过外部事件停止它。最方便的方法是构造自己的运行循环。将任务缩小并放在队列中。

自定义运行循环

我导出一个本机计时器,每隔几秒钟就会在一次downloadWithHandler methold上调用javascript处理程序,并将isCancelled设置为true。运行循环将停止,并且JSContext eval到达整个脚本的结尾并返回。

本机:

    let script = viewModel.string
    let context = EAJSContext()!
    // context will be dealloc after finish if not retain here.
    // not retain it to debugging
    // viewModel.context = context 

    DispatchQueue.global(qos: .background).async {
        // inject helper metholds 
        JavaScriptCoreHelper().config(context: context)

        // export download(handler:) method
        Emulator.configure(context: context)

        let result = context.evaluateScript(script)
        print("context return result: \(result)")
    }

脚本:

var emulator = Emulator.create();

var taskIsFinish = false;

const promiseA = new Promise( (resolve, reject) => {
    emulator.downloadWithHandler( (response) => {
        // native pass dictionary
        var isFinish = response["isFinish"];
        var isCancelled = response["isCancelled"];
        var date = response["date"];

        console.log("isFinish: " + isFinish);
        console.log("isCancelled: " + isCancelled);
        console.log("date: " + date);

        if (isFinish || isCancelled) {
            resolve(date);
        }
    });
});

promiseA
.then( (val) => {
    console.log("asynchronous logging has val: " + val)
    taskIsFinish = true
})

while(!taskIsFinish) {
    // long task in queue
    sleep(1);
    console.log('long task');
}

输出:

2020-05-10 04:07:06.766592+0800 …[34354:2831281] [interaction] … runToolbarItemPressed(_:): run triggerd
console.log: isFinish: false
console.log: isCancelled: false
console.log: date: Sun May 10 2020 04:07:06 GMT+0800 (CST)
console.log: isFinish: false
console.log: isCancelled: false
console.log: date: Sun May 10 2020 04:07:06 GMT+0800 (CST)
console.log: long task
console.log: isFinish: false
console.log: isCancelled: false
console.log: date: Sun May 10 2020 04:07:07 GMT+0800 (CST)
console.log: long task
console.log: isFinish: false
console.log: isCancelled: false
console.log: date: Sun May 10 2020 04:07:08 GMT+0800 (CST)
console.log: long task
console.log: isFinish: false
console.log: isCancelled: false
console.log: date: Sun May 10 2020 04:07:10 GMT+0800 (CST)
console.log: long task
console.log: isFinish: false
console.log: isCancelled: false
console.log: date: Sun May 10 2020 04:07:11 GMT+0800 (CST)
console.log: long task
console.log: isFinish: false
console.log: isCancelled: true
console.log: date: Sun May 10 2020 04:07:12 GMT+0800 (CST)
console.log: asynchronous logging has val: Sun May 10 2020 04:07:12 GMT+0800 (CST)
console.log: long task
console.log: isFinish: false
console.log: isCancelled: true
console.log: date: Sun May 10 2020 04:07:13 GMT+0800 (CST)
context return result: Optional(undefined)
console.log: isFinish: false
console.log: isCancelled: true
console.log: date: Sun May 10 2020 04:07:13 GMT+0800 (CST)
console.log: isFinish: false
console.log: isCancelled: true
console.log: date: Sun May 10 2020 04:07:13 GMT+0800 (CST)
2020-05-10 04:07:13.391950+0800 …[34354:2831310] [debug] EAJSContext.swift[16], deinit

((如果评估完成后上下文未取消初始化,则内存可能正在泄漏。)>

其他思考

包装本机Worker类中的上下文。并设置标志,以使该任务在任务取消时快速返回带有空结果的回调。不要保留并丢弃它。

© www.soinside.com 2019 - 2024. All rights reserved.