Reputation: 3171
Our Xcode project contains a sub-project that builds first party frameworks which we use as our standard libraries. One is built for each platform (iPhone, iPad, watchOS,...) but there is significant overlap between them (extensions for example).
In our Objective-C code in the main project, I simply have a different prefix header for each target based on its platform, and I import the relevant framework header. This means in my entire project I can use all the symbols that are in our "standard library".
I want this to happen in our Swift code as well (for both Swift and Objective-C symbols). From what I'm aware, Swift doesn't have the concept of prefix headers, so I'm needing to import the framework/module manually in each file.
What's more annoying, my imports won't just need to be
import MyFrameworkForiPhone
But because of the platform specific frameworks, with the help of Swift compiler flags, they'll need to become
#if RD_IPHONE
import MyFrameworkForiPhone
#elseif RD_IPAD
import MyFrameworkForiPad
#endif
Does anyone have any suggestions about how to cleanly work around this problem, or am I stuck with this for the time being?
Upvotes: 2
Views: 3780
Reputation: 870
[edit: oops, I answered the wrong question. This answer is for Frameworks that target multiple platforms]
The support for cross-platform frameworks is still pretty bad. In Xcode, I work as follows:
create a single source tree for my library
create subfolders for platform-specific stuff
if a class is implemented differently for different platforms, it appears in each platform subfolder (where it is supported at all)
Now create a "Target" in XCode of type "... Static Library" for each platform you want to support (I have WatchOS, iOS, and MacOS in mine). Name them differently, obviously. However, change the "Build Settings | Basic | Product Name" on every one of these static libraries to be the same, like "MyLibrary" for example.
for each source file in your library, tick the "Target Membership" in the file properties to select which the platform libraries that should include this file. Obviously, everything in the platform-specific folders should only be included in those platform targets.
for other platform-specific targets, add Library linking and Target Dependency for the platform-specific target, like "MyLibrary_MacOS" or whatever you called your library targets above.
Now you can have "import MyLibrary" in your source files and it will automagically find the one that is actually available on the platform that you are compiling. This way, you can have platform abstractions or platform-specific stuff in your library and it doesn't appear everywhere in the code, just like "Foundation."
I also add headers in there for MacOS to provide dummy implementations of WatchOS APIs that I need for testing, for example. That way, I can unit test code on MacOS.
No, this is not optimal, because a formal "Framework" compile would be better, but it is the only way I have found to do it locally with full debuggability.
If anyone else has actually used something that works better, please let me know. Please don't recommend something you haven't actually used :)
Upvotes: 0
Reputation: 791
While it may not be advisable to have separate modules for different platforms, sometimes we find ourselves in this situation and have to deal with it. Fortunately, there is one way to shorten that boilerplate...
You could create a third module, perhaps called MyFramework
that selectively includes the appropriate framework for the current platform. Such a module would only need one source file that looks just like your example above:
#if RD_IPHONE
import MyFrameworkForiPhone
#elseif RD_IPAD
import MyFrameworkForiPad
#endif
Then, every other source file would simply import MyFramework
. This works because a module will re-expose anything public from other modules it imports.
This approach also provides a sensible location for anything that the two platform-specific modules have in common. Shared code can move into this platform-agnostic module, helping you move closer to the ideal scenario.
Upvotes: 2
Reputation: 7746
I would strongly advise against creating frameworks designed only for iPhone or iPad. If there is any UI code It would likely make it impossible for an app to be resizable on iPad and there isn't any code that will compile for one and not the other.
Besides that, you're not compiling separate binaries for iPad and iPhone if it's the same app. Imports are done at compile time, so you cannot dynamically include different frameworks based on the device on which it's being installed.
If you have completely separate apps that only support iPhone or iPad (which should be avoided), you could add compiler flags to each of them to do different things with the same files.
Upvotes: 0