diff --git a/apps/toolbox/src/pages/a11y.ts b/apps/toolbox/src/pages/a11y.ts
index f4284abb3..67bdbfd2f 100644
--- a/apps/toolbox/src/pages/a11y.ts
+++ b/apps/toolbox/src/pages/a11y.ts
@@ -17,6 +17,7 @@ export class AccessibilityModel extends Observable {
accessibilityLiveRegions = AccessibilityLiveRegion;
accessibilityRole = AccessibilityRole;
accessibilityState = AccessibilityState;
+ largeImageSrc = 'https://i.picsum.photos/id/669/5000/5000.jpg?hmac=VlpchW0ODhflKm0SKOYQrc8qysLWbqKmDS1MGT9apAc';
constructor() {
super();
@@ -26,6 +27,11 @@ export class AccessibilityModel extends Observable {
const checked = (args.object as Switch).checked;
console.log(checked);
this.set('switchCheckedText', `${this.labelText} ${checked}`);
+
+ // prettier-ignore
+ this.set('largeImageSrc', checked ?
+ 'https://i.picsum.photos/id/669/5000/5000.jpg?hmac=VlpchW0ODhflKm0SKOYQrc8qysLWbqKmDS1MGT9apAc' :
+ 'https://i.picsum.photos/id/684/5000/5000.jpg?hmac=loiXO_OQ-y86XY_hc7p3qJdY39fSd9CuDM0iA_--P4Q');
}
openModal() {
diff --git a/apps/toolbox/src/pages/a11y.xml b/apps/toolbox/src/pages/a11y.xml
index e8f1f36ba..884e35e07 100644
--- a/apps/toolbox/src/pages/a11y.xml
+++ b/apps/toolbox/src/pages/a11y.xml
@@ -12,13 +12,16 @@
+
+
+
-
-
-
+
+
+
@@ -28,7 +31,7 @@
-
+
diff --git a/packages/core/ui/image/image-common.ts b/packages/core/ui/image/image-common.ts
index efce0148f..b982c0682 100644
--- a/packages/core/ui/image/image-common.ts
+++ b/packages/core/ui/image/image-common.ts
@@ -28,10 +28,16 @@ export abstract class ImageBase extends View implements ImageDefinition {
this.style.tintColor = value;
}
+ public disposeImageSource() {
+ // override in subclass
+ }
+
/**
* @internal
*/
public _createImageSourceFromSrc(value: string | ImageSource | ImageAsset): void {
+ this.disposeImageSource();
+
const originalValue = value;
const sync = this.loadMode === 'sync';
if (typeof value === 'string' || value instanceof String) {
diff --git a/packages/core/ui/image/index.ios.ts b/packages/core/ui/image/index.ios.ts
index 349bc6b4a..60ed14575 100644
--- a/packages/core/ui/image/index.ios.ts
+++ b/packages/core/ui/image/index.ios.ts
@@ -2,7 +2,7 @@ import { ImageBase, stretchProperty, imageSourceProperty, tintColorProperty, src
import { ImageSource } from '../../image-source';
import { Color } from '../../color';
import { Trace } from '../../trace';
-import { layout } from '../../utils';
+import { layout, queueGC } from '../../utils';
export * from './image-common';
@@ -24,21 +24,28 @@ export class Image extends ImageBase {
this._setNativeClipToBounds();
}
- public disposeNativeView(): void {
- super.disposeNativeView();
+ public disposeImageSource() {
+ if (this.nativeViewProtected?.image === this.imageSource?.ios) {
+ this.nativeViewProtected.image = null;
+ }
if (this.imageSource?.ios) {
this.imageSource.ios = null;
- // causes crash currently:
- // release the native UIImage
- // CFRelease(this.imageSource.ios);
}
this.imageSource = null;
+ queueGC();
+ }
+
+ public disposeNativeView(): void {
+ super.disposeNativeView();
+
if (this.nativeViewProtected?.image) {
this.nativeViewProtected.image = null;
}
+
+ this.disposeImageSource();
}
private setTintColor(value: Color) {
@@ -46,15 +53,23 @@ export class Image extends ImageBase {
if (value && this.nativeViewProtected.image && !this._templateImageWasCreated) {
this.nativeViewProtected.image = this.nativeViewProtected.image.imageWithRenderingMode(UIImageRenderingMode.AlwaysTemplate);
this._templateImageWasCreated = true;
+ queueGC();
} else if (!value && this.nativeViewProtected.image && this._templateImageWasCreated) {
this._templateImageWasCreated = false;
this.nativeViewProtected.image = this.nativeViewProtected.image.imageWithRenderingMode(UIImageRenderingMode.Automatic);
+ queueGC();
}
this.nativeViewProtected.tintColor = value ? value.ios : null;
}
}
public _setNativeImage(nativeImage: UIImage) {
+ if (this.nativeViewProtected?.image) {
+ this.nativeViewProtected.image = null;
+
+ queueGC();
+ }
+
if (this.nativeViewProtected) {
this.nativeViewProtected.image = nativeImage;
}
@@ -169,6 +184,10 @@ export class Image extends ImageBase {
}
[imageSourceProperty.setNative](value: ImageSource) {
+ if (value !== this.imageSource) {
+ this.disposeImageSource();
+ }
+
this._setNativeImage(value ? value.ios : null);
}
diff --git a/packages/core/utils/index.d.ts b/packages/core/utils/index.d.ts
index 339da5019..48ab142b3 100644
--- a/packages/core/utils/index.d.ts
+++ b/packages/core/utils/index.d.ts
@@ -187,6 +187,11 @@ export namespace ad {
*/
export function GC();
+/**
+ * An utility function that queues a garbage collection, subseqent calls will be throttled and only one gc will be executed.
+ */
+export function queueGC();
+
/**
* Releases the reference to the wrapped native object
* @param object The Java/Objective-C object to release.
diff --git a/packages/core/utils/utils-common.ts b/packages/core/utils/utils-common.ts
index 991ae0dbb..0706ac58a 100644
--- a/packages/core/utils/utils-common.ts
+++ b/packages/core/utils/utils-common.ts
@@ -3,6 +3,8 @@ import { dispatchToMainThread, isMainThread } from './mainthread-helper';
import { sanitizeModuleName } from '../ui/builder/module-name-sanitizer';
import * as layout from './layout-helper';
+import { GC } from './index';
+
export { layout };
export * from './mainthread-helper';
export * from './macrotask-scheduler';
@@ -129,3 +131,17 @@ export function mainThreadify(func: Function): (...args: any[]) => void {
executeOnMainThread(() => func.apply(this, argsToPass));
};
}
+
+let hasQueuedGC = false;
+export function queueGC() {
+ if (hasQueuedGC) {
+ return;
+ }
+
+ hasQueuedGC = true;
+
+ setTimeout(() => {
+ hasQueuedGC = false;
+ GC();
+ }, 1000);
+}