We’ve encountered build errors sporadically while importing our module’s Swift header into Objective-C. These mysterious errors were seemingly unrelated to the code we were working on. SESliderTableViewCell won’t build because I imported GC-Swift.h into GCAlerts.m. What on earth is going on? To make it even more confusing, we’ve been able to “fix” the error by […]
We’ve encountered build errors sporadically while importing our module’s Swift header into Objective-C. These mysterious errors were seemingly unrelated to the code we were working on.
SESliderTableViewCell won’t build because I imported
GCAlerts.m. What on earth is going on?
To make it even more confusing, we’ve been able to “fix” the error by creating a new Objective-C class in our project and importing
GC-Swift.h over there. We used this technique to create shims around new Swift classes that needed to talk to older Objective-C code in our app with some success.
It turns out that the connection between these files and classes, although non-obvious is actually very logical. The build time errors that Xcode gives us tells us what’s failing to build, and if we look closely, we see that as part of building
GC-Swift.h, Xcode is building
AppFriendsUI, which is in turn building
Xcode is building all of these things, because, as part of importing our swift bridging header, it needs to be able to link against anything and everything that goes into the header. Anything and everything in the bridging header, as it turns out, is quite a lot.
Something interesting is happening here: When we import the bridging header into non-ARC code, the imported header is treated as if it’s non-ARC code too. (This makes sense, because header imports are just replaced with code by the pre-processor at compile time.) As a result, those warnings are emitted, causing our project to fail to build. A failure in
AppFriendsUI should cause
GC-Swift to fail to build, but why did
AppFriendsUI not compile? (Spoiler: And why should warnings cause a failure?)
AppFriendsUI is its own Swift module, it gets its own bridging header. If we look at
AppFriendsUI-Swift.h, we’ll see that
SESlideTableViewCell is failing to compile too. If we examine
SESliderTableViewCell, we see a few errors about property attributes being missing or incorrect.
Recall that property attributes are the keywords like
strong that go in parenthesis as part of a property decleration. A warning about incorrect property attributes something that I haven’t seen in a long time, so let’s look it up online… As it turns out, prior to automatic reference counting (ARC), the compiler would warn us about missing memory management property attributes.
You might be wondering, though: If Xcode warns about missing memory management attributes, shouldn’t our app still build? Of course, warnings don’t usually cause the compiler to fail, but as part of our project we’ve told Xcode to treat warnings as errors. So, any pre-ARC code in our project would fail to compile with missing or incorrect memory-management property attributes.
So why does our app only fail some of the time after importing
GC-Swift.h? Only some of our source files are set to compile with ARC turned off. We have it enabled by default, but there’s a flag we set in our target’s build settings on a per-file basis:
-fobjc-no-arc. If any of those files imported the offending code, the error would surface.
By now we’ve seen a random compiler error, figured out what was causing it, and why it only happened sometimes. Let’s talk about a fix. In diagnosing the problem, we talked about abstracting out the code into another module, and as we discussed earlier, using a wrapper class. We could also try editing the pod generating the errors, but if we need to upgrade it, those fixes would get blown away.
These approaches work around the symptoms of the problem by abstracting away build errors to somewhere else, so they don’t get in our way. It turns out that there’s a better way to fix the root cause of the problem: Upgrade to ARC as we encounter files suffering from this problem.
After changing GCAlerts.m to compile with ARC, we were able to build and run our app with no problems.
The solution is therefore to convert those files to ARC.
If you search the web for ARC conversion, you’ll see that there’s a tool built into Xcode to do that. We have a mixed project, though, and we don’t want to convert everything at once. So if you need to convert just one or two files to ARC in a mixed project, here’s how you do it: