In the old days of iOS and OS X development, “namespacing” meant prepending Objective-C class names with a (hopefully) unique prefix to avoid conflicts. Swift mostly removes this need by providing automatic namespacing at the module level, though this can introduce an additional consideration.
Recently I began adding a Today Widget to an iOS app and ran into an odd bug. I have a custom button subclass that lives in the main app, and I also wanted to use it in the Widget, so I just added it to the Widget’s target. Each time I loaded the Widget, though, it defaulted to a plain UIButton instance and completely ignored the custom subclass despite it appearing correctly in Interface Builder.
After a few debugging dead ends, the solution started with the discovery that I could directly run a Today Widget in the simulator — I had thought the debugger needed to be attached after, which was missing some key log messages at initialization. This message was in the log:
Unknown class _TtC10Sun___Moon16SSBorderedButton in Interface Builder file.
When loading the storyboard, it wasn’t finding my button subclass. It was definitely added to the target, so why wasn’t the loader finding the subclass? It turns out there’s an additional setting that must be set in combination with the subclass name:
The Module setting needed to be set to the Today Widget — it was defaulting to the main app’s module. This setting is something new to Swift since Objective-C lacks everything related to namespacing. Ideally, this setting should default to the selected target for the storyboard file rather than the main project, but because I set the subclass value before adding the subclass to the Today Widget target it defaulted to the main app.
Radar #24011422: Setting a custom subclass in Interface Builder should warn if the subclass is not reachable by the storyboard’s/xib’s main target