NS 8.2.0+ iOS Base64 images disappearing after scrolling ListView/RadListView
Issue Description
When upgrading @nativescript/core from 8.1.5 to latest 8.2.1 (or 8.2.0), I notice that images inside ListView/RadListView are disappearing after scrolling when using base64 ImageSources on iOS. They appear again when removing the items from ObservableArray and add them again.
<ListView items="{{ items }}">
<ListView.itemTemplate>
<GridLayout columns="auto,20,*>
<Image col="0" src="{{ imageSrc }}" className="image-list"/>
<Label col="2" text="{{ title }}" verticalAlignment="center"/>
</GridLayout>
</ListView.itemTemplate>
</ListView>
export const vm = fromObject({
items: new ObservableArray([
{title: "Item 1", imageSrc: ImageSource.fromBase64Sync("/9j/4AAQSkZJRgABAQAASABIAAD/4QCMRXhpZg...")},
{title: "Item 2", imageSrc: ImageSource.fromBase64Sync("/9j/4AAQSkZJRgABAQEBLAEsAAD/7QJoUGhvdG...")},
{title: "Item 3", imageSrc: null},
//...
])
});
The output: https://user-images.githubusercontent.com/6443021/157667068-8effbe14-f17d-4360-ac4b-f8d1f2157712.mov
With nativescript/core 8.1.5, it was working as expected:
https://user-images.githubusercontent.com/6443021/157667249-c57d8be4-3b16-4e3f-9238-6efe862a557c.mov
Reproduction
Sample app to reproduce: ns-8-2-ios-image.zip
- run the app on ios
- tap the first button to navigate to the page with RadListView and base64 images
- scroll the list down and up again -> images disappearing
Relevant log output (if applicable)
-
Environment
OS: macOS 12.2.1
CPU: (12) x64 Intel(R) Core(TM) i7-9750H CPU @ 2.60GHz
Shell: /bin/zsh
node: 14.18.1
npm: 6.14.15
nativescript: 8.1.5
# android
java: 11.0.11
ndk: Not Found
apis: Not Found
build_tools: Not Found
system_images: Not Found
# ios
xcode: 13.2.1/13C100
cocoapods: 1.11.2
python: 2.7.18
python3: 3.9.7
ruby: 2.7.4
platforms:
- DriverKit 21.2
- iOS 15.2
- macOS 12.1
- tvOS 15.2
- watchOS 8.3
Dependencies
"dependencies": {
"@nativescript/core": "^8.2.1",
"nativescript-ui-listview": "^10.0.2"
},
"devDependencies": {
"@nativescript/android": "^8.2.2",
"@nativescript/ios": "^8.2.1",
"@nativescript/types": "~8.2.0",
"@nativescript/webpack": "~5.0.6",
"typescript": "~4.5.5"
}
Please accept these terms
- [X] I have searched the existing issues as well as StackOverflow and this has not been posted before
- [X] This is a bug report
- [X] I agree to follow this project's Code of Conduct
I just noticed that it may happen on Android as well, but not in the same dimenson like iOS.
https://user-images.githubusercontent.com/6443021/157669994-86a5e0dc-623d-4142-96d2-41f10c8ce910.mov
But I noticed that on ANdroid it may happen with nativescript/core 8.1.5 as well
@felixkrautschuk I think there had been some work in 8.2 regarding iOS UIImage memory leaks and clean so perhaps it could be related to this? As a temporary solution, I think you could use callbacks that return image sources. For example:
export const vm = fromObject({
items: new ObservableArray([
{title: "Item 1", getImageSrc: () => ImageSource.fromBase64Sync("/9j/4AAQSkZJRgABAQAASABIAAD/4QCMRXhpZg...")},
{title: "Item 2", getImageSrc: () => ImageSource.fromBase64Sync("/9j/4AAQSkZJRgABAQEBLAEsAAD/7QJoUGhvdG...")},
{title: "Item 3", getImageSrc: () => null},
//...
])
});
<ListView items="{{ items }}">
<ListView.itemTemplate>
<GridLayout columns="auto,20,*>
<Image col="0" src="{{ getImageSrc() }}" className="image-list"/>
<Label col="2" text="{{ title }}" verticalAlignment="center"/>
</GridLayout>
</ListView.itemTemplate>
</ListView>
Hope it works.
@DimitrisRK Thanks for your feedback. I checked that out in the sample app and it seems to work for ListView.
But there are some issues when using RadListView (which is actually our main use-case).
On iOS, the images do not disappear anymore when scrolling, but I see some binding errors:
CONSOLE ERROR: Binding: Error: Cannot perform a call using a null or undefined property at Image(58)@rlv-page.xml:12:21; CONSOLE ERROR: Binding: Error: Cannot perform a call using a null or undefined property at Image(61)@rlv-page.xml:12:21; CONSOLE ERROR: Binding: Error: Cannot perform a call using a null or undefined property at Image(64)@rlv-page.xml:12:21; CONSOLE ERROR: Binding: Error: Cannot perform a call using a null or undefined property at Image(67)@rlv-page.xml:12:21; ...
On Android, the app is crashing
System.err: Error: The method setNativeSource() expects android.graphics.Bitmap instance. System.err: System.err: StackTrace: System.err: setNativeSource(file: app/webpack:/ns-8-2-ios-image/node_modules/@nativescript/core/image-source/index.android.js:225:0) System.err: at ImageSource(file: app/webpack:/ns-8-2-ios-image/node_modules/@nativescript/core/image-source/index.android.js:31:0) System.err: at _createImageSourceFromSrc(file: app/webpack:/ns-8-2-ios-image/node_modules/@nativescript/core/ui/image/image-common.js:113:0) System.err: at _createImageSourceFromSrc(file: app/webpack:/ns-8-2-ios-image/node_modules/@nativescript/core/ui/image/index.android.js:110:0) System.err: at [src:setNative](file: app/webpack:/ns-8-2-ios-image/node_modules/@nativescript/core/ui/image/index.android.js:166:0) System.err: at applyAllNativeSetters(file: app/webpack:/ns-8-2-ios-image/node_modules/@nativescript/core/ui/core/properties/index.js:1136:0) System.err: at initNativeView(file: app/webpack:/ns-8-2-ios-image/node_modules/@nativescript/core/ui/core/properties/index.js:1079:0) System.err: at onResumeNativeUpdates(file: app/webpack:/ns-8-2-ios-image/node_modules/@nativescript/core/ui/core/view-base/index.js:740:22) System.err: at _resumeNativeUpdates(file: app/webpack:/ns-8-2-ios-image/node_modules/@nativescript/core/ui/core/view-base/index.js:280:0) System.err: at onLoaded(file: app/webpack:/ns-8-2-ios-image/node_modules/@nativescript/core/ui/core/view-base/index.js:235:0) System.err: at onLoaded(file: app/webpack:/ns-8-2-ios-image/node_modules/@nativescript/core/ui/core/view/view-common.js:107:0) System.err: at onLoaded(file: app/webpack:/ns-8-2-ios-image/node_modules/@nativescript/core/ui/core/view/index.android.js:309:0) System.err: at (file: app/webpack:/ns-8-2-ios-image/node_modules/@nativescript/core/ui/core/view-base/index.js:318:0) System.err: at callFunctionWithSuper(file: app/webpack:/ns-8-2-ios-image/node_modules/@nativescript/core/ui/core/view-base/index.js:312:0) System.err: at callLoaded(file: app/webpack:/ns-8-2-ios-image/node_modules/@nativescript/core/ui/core/view-base/index.js:318:0) System.err: at loadView(file: app/webpack:/ns-8-2-ios-image/node_modules/@nativescript/core/ui/core/view-base/index.js:458:0) System.err: at (file: app/webpack:/ns-8-2-ios-image/node_modules/@nativescript/core/ui/core/view-base/index.js:237:0) System.err: at eachChildView(file: app/webpack:/ns-8-2-ios-image/node_modules/@nativescript/core/ui/layouts/layout-base-common.js:101:0) System.err: at eachChild(file: app/webpack:/ns-8-2-ios-image/node_modules/@nativescript/core/ui/core/view/view-common.js:772:0) System.err: at onLoaded(file: app/webpack:/ns-8-2-ios-image/node_modules/@nativescript/core/ui/core/view-base/index.js:236:0) System.err: at onLoaded(file: app/webpack:/ns-8-2-ios-image/node_modules/@nativescript/core/ui/core/view/view-common.js:107:0) System.err: at onLoaded(file: app/webpack:/ns-8-2-ios-image/node_modules/@nativescript/core/ui/core/view/index.android.js:309:0) System.err: at (file: app/webpack:/ns-8-2-ios-image/node_modules/@nativescript/core/ui/core/view-base/index.js:318:0) System.err: at callFunctionWithSuper(file: app/webpack:/ns-8-2-ios-image/node_modules/@nativescript/core/ui/core/view-base/index.js:312:0) System.err: at callLoaded(file: app/webpack:/ns-8-2-ios-image/node_modules/@nativescript/core/ui/core/view-base/index.js:318:0) System.err: at loadView(file: app/webpack:/ns-8-2-ios-image/node_modules/@nativescript/core/ui/core/view-base/index.js:458:0) System.err: at (file: app/webpack:/ns-8-2-ios-image/node_modules/@nativescript/core/ui/core/view-base/index.js:237:0) System.err: at eachChildView(file: app/webpack:/ns-8-2-ios-image/node_modules/@nativescript/core/ui/layouts/layout-base-common.js:101:0) System.err: at eachChild(file: app/webpack:/ns-8-2-ios-image/node_modules/@nativescript/core/ui/core/view/view-common.js:772:0) System.err: at onLoaded(file: app/webpack:/ns-8-2-ios-image/node_modules/@nativescript/core/ui/core/view-base/index.js:236:0) System.err: at onLoaded(file: app/webpack:/ns-8-2-ios-image/node_modules/@nativescript/core/ui/core/view/view-common.js:107:0) System.err: at onLoaded(file: app/webpack:/ns-8-2-ios-image/node_modules/@nativescript/core/ui/core/view/index.android.js:309:0) System.err: at (file: app/webpack:/ns-8-2-ios-image/node_modules/@nativescript/core/ui/core/view-base/index.js:318:0) System.err: at callFunctionWithSuper(file: app/webpack:/ns-8-2-ios-image/node_modules/@nativescript/core/ui/core/view-base/index.js:312:0) System.err: at callLoaded(file: app/webpack:/ns-8-2-ios-image/node_modules/@nativescript/core/ui/core/view-base/index.js:318:0) System.err: at loadView(file: app/webpack:/ns-8-2-ios-image/node_modules/@nativescript/core/ui/core/view-base/index.js:458:0) System.err: at _addViewCore(file: app/webpack:/ns-8-2-ios-image/node_modules/@nativescript/core/ui/core/view-base/index.js:453:0) System.err: at _addView(file: app/webpack:/ns-8-2-ios-image/node_modules/@nativescript/core/ui/core/view-base/index.js:439:0) System.err: at ListViewAdapter.onCreateViewHolder(file: app/webpack:/ns-8-2-ios-image/node_modules/nativescript-ui-listview/index.android.js:120:0) System.err: at com.tns.Runtime.callJSMethodNative(Native Method) System.err: at com.tns.Runtime.dispatchCallJSMethodNative(Runtime.java:1302) System.err: at com.tns.Runtime.callJSMethodImpl(Runtime.java:1188) System.err: at com.tns.Runtime.callJSMethod(Runtime.java:1175) System.err: at com.tns.Runtime.callJSMethod(Runtime.java:1153) System.err: at com.tns.Runtime.callJSMethod(Runtime.java:1149) System.err: at com.tns.gen.com.telerik.widget.list.ListViewAdapter_vendor_54258_28_ListViewAdapter.onCreateViewHolder(ListViewAdapter_vendor_54258_28_ListViewAdapter.java:41) System.err: at com.telerik.widget.list.ListViewWrapperAdapter.onCreateViewHolder(ListViewWrapperAdapter.java:468) System.err: at com.telerik.widget.list.ListViewWrapperAdapter.onCreateViewHolder(ListViewWrapperAdapter.java:20) System.err: at androidx.recyclerview.widget.RecyclerView$Adapter.createViewHolder(RecyclerView.java:7078) System.err: at androidx.recyclerview.widget.RecyclerView$Recycler.tryGetViewHolderForPositionByDeadline(RecyclerView.java:6235) System.err: at androidx.recyclerview.widget.RecyclerView$Recycler.getViewForPosition(RecyclerView.java:6118) System.err: at androidx.recyclerview.widget.RecyclerView$Recycler.getViewForPosition(RecyclerView.java:6114) System.err: at androidx.recyclerview.widget.LinearLayoutManager$LayoutState.next(LinearLayoutManager.java:2303) System.err: at androidx.recyclerview.widget.LinearLayoutManager.layoutChunk(LinearLayoutManager.java:1627) System.err: at androidx.recyclerview.widget.LinearLayoutManager.fill(LinearLayoutManager.java:1587) System.err: at androidx.recyclerview.widget.LinearLayoutManager.onLayoutChildren(LinearLayoutManager.java:665) System.err: at androidx.recyclerview.widget.RecyclerView.dispatchLayoutStep2(RecyclerView.java:4134) System.err: at androidx.recyclerview.widget.RecyclerView.dispatchLayout(RecyclerView.java:3851) System.err: at androidx.recyclerview.widget.RecyclerView.onLayout(RecyclerView.java:4404) System.err: at com.telerik.widget.list.RadListView.onLayout(RadListView.java:600) System.err: at android.view.View.layout(View.java:21912) System.err: at android.view.ViewGroup.layout(ViewGroup.java:6260) System.err: at android.widget.FrameLayout.layoutChildren(FrameLayout.java:332) System.err: at android.widget.FrameLayout.onLayout(FrameLayout.java:270) System.err: at android.view.View.layout(View.java:21912) System.err: at android.view.ViewGroup.layout(ViewGroup.java:6260) System.err: at org.nativescript.widgets.CommonLayoutParams.layoutChild(CommonLayoutParams.java:222) System.err: at org.nativescript.widgets.GridLayout.onLayout(GridLayout.java:351) System.err: at android.view.View.layout(View.java:21912) System.err: at android.view.ViewGroup.layout(ViewGroup.java:6260) System.err: at org.nativescript.widgets.CommonLayoutParams.layoutChild(CommonLayoutParams.java:222) System.err: at org.nativescript.widgets.GridLayout.onLayout(GridLayout.java:351) System.err: at android.view.View.layout(View.java:21912) System.err: at android.view.ViewGroup.layout(ViewGroup.java:6260) System.err: at org.nativescript.widgets.CommonLayoutParams.layoutChild(CommonLayoutParams.java:222) System.err: at org.nativescript.widgets.ContentLayout.onLayout(ContentLayout.java:73) System.err: at android.view.View.layout(View.java:21912) System.err: at android.view.ViewGroup.layout(ViewGroup.java:6260) System.err: at android.widget.FrameLayout.layoutChildren(FrameLayout.java:332) System.err: at android.widget.FrameLayout.onLayout(FrameLayout.java:270) System.err: at android.view.View.layout(View.java:21912) System.err: at android.view.ViewGroup.layout(ViewGroup.java:6260) System.err: at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1829) System.err: at android.widget.LinearLayout.layoutVertical(LinearLayout.java:1673) System.err: at android.widget.LinearLayout.onLayout(LinearLayout.java:1582) System.err: at android.view.View.layout(View.java:21912) System.err: at android.view.ViewGroup.layout(ViewGroup.java:6260) System.err: at android.widget.FrameLayout.layoutChildren(FrameLayout.java:332) System.err: at android.widget.FrameLayout.onLayout(FrameLayout.java:270) System.err: at android.view.View.layout(View.java:21912) System.err: at android.view.ViewGroup.layout(ViewGroup.java:6260) System.err: at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1829) System.err: at android.widget.LinearLayout.layoutVertical(LinearLayout.java:1673) System.err: at android.widget.LinearLayout.onLayout(LinearLayout.java:1582) System.err: at android.view.View.layout(View.java:21912) System.err: at android.view.ViewGroup.layout(ViewGroup.java:6260) System.err: at android.widget.FrameLayout.layoutChildren(FrameLayout.java:332) System.err: at android.widget.FrameLayout.onLayout(FrameLayout.java:270) System.err: at com.android.internal.policy.DecorView.onLayout(DecorView.java:779) System.err: at android.view.View.layout(View.java:21912) System.err: at android.view.ViewGroup.layout(ViewGroup.java:6260) System.err: at android.view.ViewRootImpl.performLayout(ViewRootImpl.java:3080) System.err: at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:2590) System.err: at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1721) System.err: at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:7598) System.err: at android.view.Choreographer$CallbackRecord.run(Choreographer.java:966) System.err: at android.view.Choreographer.doCallbacks(Choreographer.java:790) System.err: at android.view.Choreographer.doFrame(Choreographer.java:725) System.err: at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:951) System.err: at android.os.Handler.handleCallback(Handler.java:883) System.err: at android.os.Handler.dispatchMessage(Handler.java:100) System.err: at android.os.Looper.loop(Looper.java:214) System.err: at android.app.ActivityThread.main(ActivityThread.java:7356) System.err: at java.lang.reflect.Method.invoke(Native Method) System.err: at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:492) System.err: at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:930)
@DimitrisRK Thanks for your feedback. I checked that out in the sample app and it seems to work for ListView.
But there are some issues when using RadListView (which is actually our main use-case).
On iOS, the images do not disappear anymore when scrolling, but I see some binding errors:
CONSOLE ERROR: Binding: Error: Cannot perform a call using a null or undefined property at Image(58)@rlv-page.xml:12:21; CONSOLE ERROR: Binding: Error: Cannot perform a call using a null or undefined property at Image(61)@rlv-page.xml:12:21; CONSOLE ERROR: Binding: Error: Cannot perform a call using a null or undefined property at Image(64)@rlv-page.xml:12:21; CONSOLE ERROR: Binding: Error: Cannot perform a call using a null or undefined property at Image(67)@rlv-page.xml:12:21; ...
On Android, the app is crashing
Yes, it seems RadListView takes a little bit to load context for items and call expressions are quite strict in XML. You can make your call null-safe using this syntax:
{{ getImageSrc?.() }}
This will make call return undefined but android may still not like it.
Thanks, that seems to do the trick!
watching