Monday, June 29, 2020

SwiftPM and Resources

Last year I wrote about the sad state of dependency management for iOS projects. Later this year Xcode 12 will be released and it will address a couple of the big limitations of the Swift Package Manager (SwiftPM). I won't go into much detail about how they work, but you can watch a couple of great (and short!) WWDC videos about Resources and Localization and Binary Frameworks.

Last week I spent some time with the Xcode 12 beta trying the new support for resources, and even had a few great lab appointments with Apple engineers. Here are some observations. 

Resources

Xcode does a good job of bundling resources found among your sources, if it knows what to do with them. It automatically processes things like Xibs and asset catalogs. For things that it doesn't know about, you can tell it what to do in a list of resources for each target in Package.swift. See the aforementioned video for details. 

Bundle.module

If you are converting an existing framework that contains resources to SwiftPM, you'll have to make some adjustments. In a framework that is built from a traditional Xcode project, it is common to load resources such as images and Xibs using Bundle(for: AnyClass). This initializer does not work in a Swift package. Instead, Swift package code should use Bundle.module. While this is new with Xcode 12, thankfully it is backward deployable and can by used by iOS versions prior to  iOS 14. 

There is a catch though. Bundle.module is only available when building a Swift package. So, an xcodeproj framework can't use Bundle.module and has to continue to use Bundle(for: AnyClass), but a Swift package can't use Bundle(for: AnyClass) and has to use Bundle.module. This is a problem for many framework vendors that will need to support Carthage and SwiftPM concurrently for some time. It is also a problem for internal frameworks as we work toward SwiftPM, but will continue to build frameworks as Xcode projects until Xcode 12 ships. One solution is to migrate existing code to Bundle.module, and then add something like this to your project: 

#if !SWIFT_PACKAGE
extension Bundle {
    class BundleClass { }
    static let module = Bundle(for: BundleClass.self)
}
#endif

This provides an alternate implementation of Bundle.module when not building with SwiftPM. Perhaps this will be resolved before Xcode 12 ships (FB7792343 for Apple folks). 

Interface Builder

Although Xibs are now being properly copied into the target bundle, I noticed they weren't being loaded properly at runtime. Eventually I determined that I have to uncheck "Inherit Module From Target" for any custom views that are used. 
In order to make sure I caught all instances of this, I edited a lot of Xibs in a text editor. I suspect the need to uncheck "Inherit Module From Target" is a bug (FB7793693). Hopefully it will be fixed eventually. 

Testing... 

The trouble with both the Bundle(for: AnyClass) change and the Interface Builder custom class issue, is that these problems are not caught at compile time. Both result in runtime bugs or crashes. Also, these types of problems are often not covered by unit tests. If you are converting an existing framework with resources to SwiftPM, you'll need to carefully audit the project and test thoroughly. 

A Light at the End of the Tunnel

Many framework vendors already support SwiftPM. Hopefully the new support for resources and binary frameworks will enabled the rest to adopt SwiftPM soon. I look forward to fully embracing SwiftPM later this year. 


Thursday, May 21, 2020

Home Office

Spring of 2020 was defined by the COVID-19 pandemic. My job, like many others, switched to have everyone work from home for several months. I feel very fortunate to have a nice dedicated home office to work from.

Coincidentally, I began upgrading my office in December 2019 by ordering a new desk and some other items. As a result, by the time we started working from home in March the office was in good shape.

The office is a 10x11 foot space with two desks.

My desk is the Uplift 60" with curved bamboo top. It is quite stable and I find the beveled curve to be very comfortable.

The monitor is the Dell U2720Q. If Apple ever ships a 5K display I will probably get it. Until then I'll probably live with 4K. The display is really good and I like that it has a foot that is smaller than most displays. This allows me to push my keyboard farther forward and also means the display itself is a more comfortable distance. The display delivers 90W of power over USB-C, but I don't use the power delivery because the display is plugged into a dock.

The dock is the 15-port CalDigit TS3 Plus. It works really well and has the unique advantage of a vertical orientation. That means it takes up very little desk space. As you can see, it currently resides on the monitor's foot. The dock allows me to connect to my gigabit fiber internet connection via ethernet instead of WiFi.

My chair is a HON 7808 "High Back High Performance Executive Chair" that I picked up at an office surplus sale for $20. I've tried many chairs by Herman Miller and others while at various jobs, but none of them are as comfortable as my old chair. John Siracusa would be pleased to know that I removed the arms several years ago. Office chairs are better without arms.

The windows to the front and left of the desk bring in light so that I don't look like I'm in the witness protection program while in Zoom meetings. The window to the left faces north and I enjoy the view of Mount Timpanogos. Here are some photos taken from that window with an iPhone.


I also have a treadmill desk that I built a few years ago. I find that I can operate the computer well while walking at 2mph. Some days I walk 4 miles while working.

When I'm ready for a break I swim laps in the pool.