Post

Replies

Boosts

Views

Activity

[tvOS] ScrollView with Text does not scroll
I'm trying to do something so seemingly basic, yet I can't get it to work and I'm flummoxed. In a basic, vanilla SwiftUI app for tvOS, embed a single Text element with a very long string (hundreds of lines) in it: struct ContentView: View { var body: some View { ScrollView(.vertical) { Text(veryLargeString) .focusable() } } } Then fire up the app on tvOS, and it will not scroll. No matter what I do. Pressing arrow keys, swiping fast with my thumb, and nothing. It will not move. Ironically, in the Xcode SwiftUI Preview window—it does scroll, so that's always a fun tease. What I do know is that the focus engine is throwing a few errors, so it's leading me to believe the issue is with how I have the focusable element attached. I'm using a combination of -UIFocusLoggingEnabled YES as well as listening for UIFocusSystem.movementDidFailNotification. Unfortunately since this is SwiftUI, the notification failure and debugging logs aren't really all that actionable. Help appreciated!
1
1
961
Mar ’24
Image decompression strategies for performance
I've been exploring various solutions to avoid image decompression on the main thread in order to speed up rendering images. The developer community has previously shared various ways of preloading or inflating images on the background before rendering them, and most of the examples out there still work today with varying degrees of speed. See cocoanetics dot com/2011/10/avoiding-image-decompression-sickness/, gist dot github dot com/steipete/1144242, and github dot com/Alamofire/AlamofireImage/blob/3e8edbeb75227f8542aa87f90240cf0424d6362f/Source/UIImage%2BAlamofireImage.swift#L113. What's unfortunate is that none of the decompression techniques are documented, so the community is basing these assertions off of trial and error and hoping they don't regress between iOS versions. And what's more, is that some solutions are potentially ripe with error, likely missing critical alpha data, scale, orientation, or other bitmap info that might produce artifacts in the final rendered image. In our situation, we are already served derivatives of images from the server that are exactly the size that they will be rendered. But we have found through profiling in instruments that there is a huge performance win by pre-inflating the images on a background thread. So we are left with deciding what approach to take for inflation. In order to validate the inflation is working, there are a few ways to observe the decompression happen during runtime. Here is a typical backtrace of seeing PNG decompression: &#9;15 CoreFoundation 209.0&#9;CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION &#9;14 QuartzCore 180.0&#9;CA::Transaction::observer_callback(__CFRunLoopObserver*, unsigned long, void*) &#9;13 QuartzCore 180.0&#9;CA::Transaction::commit() &#9;12 QuartzCore 180.0&#9;CA::Context::commit_transaction(CA::Transaction*, double) &#9;11 QuartzCore 180.0&#9;CA::Layer::prepare_commit(CA::Transaction*) &#9;10 QuartzCore 180.0&#9;CA::Render::prepare_image(CGImage*, CGColorSpace*, unsigned int, double) &#9; 9 QuartzCore 180.0&#9;CA::Render::copy_image(CGImage*, CGColorSpace*, unsigned int, double, double) &#9; 8 ImageIO 180.0&#9;IIOImageProviderInfo::CopyImageBlockSetWithOptions(void*, CGImageProvider*, CGRect, CGSize, __CFDictionary const*) &#9; 7 ImageIO 180.0&#9;IIO_Reader::CopyImageBlockSetProc(void*, CGImageProvider*, CGRect, CGSize, __CFDictionary const*) &#9; 6 ImageIO 180.0&#9;PNGReadPlugin::copyImageBlockSet(InfoRec*, CGImageProvider*, CGRect, CGSize, __CFDictionary const*) &#9; 5 ImageIO 180.0&#9;PNGReadPlugin::DecodeUncomposedFrames(IIOImageRead*, GlobalPNGInfo*, ReadPluginData const&amp;, PNGPluginData const&amp;, std::1::vector&lt;IIODecodeFrameParams, std::1::allocator<IIODecodeFrameParams&gt; >&amp;) &#9; 4 ImageIO 180.0&#9;PNGReadPlugin::DecodeFrameStandard(IIOImageReadSession*, ReadPluginData const&amp;, PNGPluginData const&amp;, IIODecodeFrameParams&amp;) &#9; 3 ImageIO 180.0&#9;_cg_png_read_row &#9; 2 ImageIO 159.0&#9;png_read_IDAT_data For any readers, in lldb, calling: (lldb) br s -n _ZN13PNGReadPlugin22DecodeUncomposedFramesEP12IIOImageReadP13GlobalPNGInfoRK14ReadPluginDataRK13PNGPluginDataRNSt3__16vectorI20IIODecodeFrameParamsNSA_9allocatorISC_EEEE Breakpoint 1: where = ImageIO`PNGReadPlugin::DecodeUncomposedFrames(IIOImageRead*, GlobalPNGInfo*, ReadPluginData const&amp;, PNGPluginData const&amp;, std::1::vector&lt;IIODecodeFrameParams, std::1::allocator<IIODecodeFrameParams&gt; >&amp;), address = 0x00007fff2615e4d4 This will set a symbolic breakpoint that will TRAP on PNGReadPlugin::DecodeUncomposedFrames Here is a typical backtrace of seeing JPEG decompression: &#9;16 CoreFoundation 13.0&#9;CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION &#9;15 QuartzCore 13.0&#9;CA::Transaction::observer_callback(__CFRunLoopObserver*, unsigned long, void*) &#9;14 QuartzCore 12.0&#9;CA::Transaction::commit() &#9;13 QuartzCore 12.0&#9;CA::Context::commit_transaction(CA::Transaction*, double) &#9;12 QuartzCore 12.0&#9;CA::Layer::prepare_commit(CA::Transaction*) &#9;11 QuartzCore 12.0&#9;CA::Render::prepare_image(CGImage*, CGColorSpace*, unsigned int, double) &#9;10 QuartzCore 12.0&#9;CA::Render::copy_image(CGImage*, CGColorSpace*, unsigned int, double, double) &#9; 9 ImageIO 12.0&#9;IIOImageProviderInfo::CopyImageBlockSetWithOptions(void*, CGImageProvider*, CGRect, CGSize, __CFDictionary const*) &#9; 8 ImageIO 12.0&#9;IIO_Reader::CopyImageBlockSetProc(void*, CGImageProvider*, CGRect, CGSize, __CFDictionary const*) &#9; 7 ImageIO 12.0&#9;AppleJPEGReadPlugin::copyImageBlockSet(InfoRec*, CGImageProvider*, CGRect, CGSize, __CFDictionary const*) &#9; 6 AppleJPEG 11.0&#9;applejpeg_decode_image_all &#9; 5 AppleJPEG 10.0&#9;aj_decode_all_mt &#9; 4 AppleJPEG 10.0&#9;aj_decode_all &#9; 3 AppleJPEG 6.0&#9;fill_coeff_buffer &#9; 2 AppleJPEG 6.0&#9;aj_mcu_decode &#9; 1 AppleJPEG 5.0&#9;aj_block_decode &#9; 0 AppleJPEG 2.0&#9;aj_huffman_decode_ac_s1 For any readers, in lldb, calling: (lldb) br s -n _ZN19AppleJPEGReadPlugin17copyImageBlockSetEP7InfoRecP15CGImageProvider6CGRect6CGSizePK14__CFDictionary Breakpoint 1: where = ImageIO`AppleJPEGReadPlugin::copyImageBlockSet(InfoRec*, CGImageProvider*, CGRect, CGSize, __CFDictionary const*), address = 0x00007fff262a53b8 This will set a symbolic breakpoint that will TRAP on AppleJPEGReadPlugin::copyImageBlockSet
1
2
1.7k
Jul ’20