@ccc I will post something in a few days when I clean some things up. I created an endless loop calling a function that wrote a large amount of data to a BytesIO. No crash. I downloaded objgraph, and this never showed any increase in BytesIO objects.
My attempt at writing an image viewer that uses pil2ui failed after 4 photos (with or without del bIO) because of apparently a bad image in my photos (at least one that PIL choked on). I will say that, in the case of displaying photos assets, one should be using .get_ui_image instead of .get_image. That avoids any round trip through PIL, which is probably where any leaks or bugs occur. A simple image viewer using get_ui_image ran for longer than I cared to wait without a crash.
Creating ui.Images also requires some care, because these might not get gc'd automatically. I believe the best practice is to include a with objc_util.autoreleasepool(): when many UIImages are created -- though I haven't had time to explore whether setting the imageview image causes the old image to get leaked (in which case it would be necessary to manually handle the deallocation of the UIImage object)