My main activity of 2019 was a port of the Mental Canvas 3D drawing tool from Windows to iOS. About 75% of my effort was user interface code, maybe 15% on graphics and 10% other platform issues.
What’s interesting about our porting approach? Well, it’s just an unusual mix:
- It’s a UWP (Universal Windows Platform) app. UWP was Microsoft’s effort to modernize Win32 and add iOS mobile paradigms, so it is already touch-centric, relatively sandboxed and has a more mobile-like lifecycle
- We didn’t use React Native, Flutter, Electron, Xamarin, Qt or even Fuschia’s namesake Pink. We just… wrote some native code. And a lightweight abstraction layer.
- We completed the porting effort in seven months, with three developers.
- We stayed with the MVVM architecture that is the norm on Windows. Many iOS developers would call that… exceptionally ok
- We didn’t use the latest and greatest Swift tools, just plain old C++11 and Objective-C for the most part. We didn’t switch to SwiftUI when it was released half way through our port.
What combination of circumstances led to this approach? Mostly just a real life constraint: a desire to rewrite/redesign as little working code as possible, and keep the codebase’s size down.
Continue reading A Windows to iOS Port →
- Starting Point
- UI Framework Choice
- Restructuring the UI Thread
- Lightweight iOS Bindings
- What About SwiftUI?
- Incremental Porting
- The Upshot: Code Reuse
At Mental Canvas, Dave Burke and I recently resolved a memory leak bug in our iOS app using the Metal graphics libraries. Memory management on Metal has had a few good WWDC talks but has surprisingly little chatter on the web, so I thought I’d share our process and findings.
- The issue: a transient memory spike
- iOS / iPadOS memory limits
- Forming hypotheses
- Tools at hand
The issue: a transient memory spike
Our sketching app does a lot of rendering to intermediate, offscreen textures. In the process, we generate (and quickly discard) a lot of intermediate textures. A lot of that rendering happens in a continuous batch on a dedicated thread, without yielding execution back to the operating system.
A consequence of that behavior: our memory footprint grows rapidly until we hit the critical threshold — on a 3 GB iPad Air, about 1.8 GB — and then iOS summarily kills the app. From our app’s perspective, memory footprint is only growing gradually, as most of the memory usage is temporary intermediate rendertargets; they should be freed and available for reuse. But from the operating system’s perspective, it considers all of those temporaries to still be in use.
Which led us to the question: why? And how do we figure out which temporaries are leaking, and which Metal flag / call will allow us to return that data to the operating system?
Continue reading Metal Memory Debugging →