FazBrowse GitHub Viewer | Trending |
URL:
| Home
Tools: [Download Repo ZIP]   [Original HTTPS Page]

fix(devtools-ios): Ensure UI modifications run on main thread · NativeScript/NativeScript@c60f74d · GitHub

Commit c60f74d

Browse files
committed
fix(devtools-ios): Ensure UI modifications run on main thread
Modifications to the UI can only be made from the main thread. Since {N} 5.3.0 all debugger protocol messages are processed by the worker thread that receives them in iOS. refs #7219, NativeScript/ios-jsc#1101
1 parent f51bb11 commit c60f74d

6 files changed

Lines changed: 87 additions & 7 deletions

File tree

‎tests/app/utils/utils-tests.ts‎

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,38 @@ export function test_releaseNativeObject_canBeCalledWithNativeObject() {
1818
}
1919
};
2020

21+
22+
export function test_executeOnMainThread_Works(done: Function) {
23+
utils.executeOnMainThread(() => {
24+
try {
25+
TKUnit.assertTrue(utils.isMainThread());
26+
done();
27+
} catch (e) {
28+
done(e);
29+
}
30+
});
31+
}
32+
33+
export function test_mainThreadify_PassesArgs(done: Function) {
34+
const expectedN = 434;
35+
const expectedB = true;
36+
const expectedS = "string";
37+
const f = utils.mainThreadify(function (n: number, b: boolean, s: string) {
38+
try {
39+
TKUnit.assertTrue(utils.isMainThread());
40+
TKUnit.assertEqual(n, expectedN);
41+
TKUnit.assertEqual(b, expectedB);
42+
TKUnit.assertEqual(s, expectedS);
43+
done();
44+
} catch (e) {
45+
done(e);
46+
}
47+
});
48+
49+
f(expectedN, expectedB, expectedS);
50+
}
51+
52+
2153
function test_releaseNativeObject_canBeCalledWithNativeObject_iOS() {
2254
let deallocated = false;
2355
const obj = new ((<any>NSObject).extend({

‎tns-core-modules/debugger/devtools-elements.common.ts‎

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { getNodeById } from "./dom-node";
22

33
// Needed for typings only
44
import { ViewBase } from "../ui/core/view-base";
5+
import { mainThreadify } from "../utils/utils";
56

67
// Use lazy requires for core modules
78
const frameTopmost = () => require("../ui/frame").topmost();
@@ -11,7 +12,7 @@ function unsetViewValue(view, name) {
1112
if (!unsetValue) {
1213
unsetValue = require("../ui/core/properties").unsetValue;
1314
}
14-
15+
1516
view[name] = unsetValue;
1617
}
1718

@@ -30,10 +31,10 @@ export function getDocument() {
3031
if (!topMostFrame) {
3132
return undefined;
3233
}
33-
34+
3435
try {
3536
topMostFrame.ensureDomNode();
36-
37+
3738
} catch (e) {
3839
console.log("ERROR in getDocument(): " + e);
3940
}
@@ -49,7 +50,7 @@ export function getComputedStylesForNode(nodeId): Array<{ name: string, value: s
4950
return [];
5051
}
5152

52-
export function removeNode(nodeId) {
53+
export const removeNode = mainThreadify(function removeNode(nodeId) {
5354
const view = getViewById(nodeId);
5455
if (view) {
5556
// Avoid importing layout and content view
@@ -63,9 +64,9 @@ export function removeNode(nodeId) {
6364
console.log("Can't remove child from " + parent);
6465
}
6566
}
66-
}
67+
});
6768

68-
export function setAttributeAsText(nodeId, text, name) {
69+
export const setAttributeAsText = mainThreadify(function setAttributeAsText(nodeId, text, name) {
6970
const view = getViewById(nodeId);
7071
if (view) {
7172
// attribute is registered for the view instance
@@ -93,4 +94,4 @@ export function setAttributeAsText(nodeId, text, name) {
9394

9495
view.domNode.loadAttributes();
9596
}
96-
}
97+
});

‎tns-core-modules/utils/utils-common.ts‎

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import * as types from "./types";
2+
import { executeOnMainThread } from "./utils"
23

34
export const RESOURCE_PREFIX = "res://";
45
export const FILE_PREFIX = "file:///";
@@ -154,3 +155,10 @@ export function hasDuplicates(arr: Array<any>): boolean {
154155
export function eliminateDuplicates(arr: Array<any>): Array<any> {
155156
return Array.from(new Set(arr));
156157
}
158+
159+
export function mainThreadify(func: Function): (...args: any[]) => void {
160+
return function () {
161+
const argsToPass = arguments;
162+
executeOnMainThread(() => func.apply(this, argsToPass));
163+
}
164+
}

‎tns-core-modules/utils/utils.android.ts‎

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -372,3 +372,14 @@ Please ensure you have your manifest correctly configured with the FileProvider.
372372
return false;
373373
}
374374
}
375+
376+
export function executeOnMainThread(func: () => void) {
377+
new android.os.Handler(android.os.Looper.getMainLooper())
378+
.post(new java.lang.Runnable({
379+
run: func
380+
}));
381+
}
382+
383+
export function isMainThread(): Boolean {
384+
return android.os.Looper.myLooper() === android.os.Looper.getMainLooper();
385+
}

‎tns-core-modules/utils/utils.d.ts‎

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -269,6 +269,26 @@ export function GC();
269269
*/
270270
export function releaseNativeObject(object: any /*java.lang.Object | NSObject*/);
271271

272+
/**
273+
* Dispatches the passed function for execution on the main thread
274+
* @param func The function to execute on the main thread.
275+
*/
276+
export function executeOnMainThread(func: Function);
277+
278+
/**
279+
* Returns a function wrapper which executes the supplied function on the main thread.
280+
* The wrapper behaves like the original function and passes all of its arguments BUT
281+
* discards its return value.
282+
* @param func The function to execute on the main thread
283+
* @returns The wrapper function which schedules execution to the main thread
284+
*/
285+
export function mainThreadify(func: Function): (...args: any[]) => void
286+
287+
/**
288+
* @returns Boolean value indicating whether the current thread is the main thread
289+
*/
290+
export function isMainThread(): boolean
291+
272292
/**
273293
* Returns true if the specified path points to a resource or local file.
274294
* @param path The path.

‎tns-core-modules/utils/utils.ios.ts‎

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,14 @@ export function openUrl(location: string): boolean {
159159
return false;
160160
}
161161

162+
export function executeOnMainThread(func: () => void) {
163+
NSOperationQueue.mainQueue.addOperationWithBlock(func);
164+
}
165+
166+
export function isMainThread(): Boolean {
167+
return NSThread.isMainThread;
168+
}
169+
162170
class UIDocumentInteractionControllerDelegateImpl extends NSObject implements UIDocumentInteractionControllerDelegate {
163171
public static ObjCProtocols = [UIDocumentInteractionControllerDelegate];
164172

0 commit comments

Comments
 (0)

Back | FazBrowse Home | New Git URL