contributors |
---|
zntfdr |
- ✅ model code: no conversion nor data loss when shared across platform
- ❌ view code: different gestures, HIG, display size, flows
- ❓ controller code: it depends on the kind of controllers
We could use shimming:
#if TARGET_OS_IPHONE
@interface MyAwesomeView : UIView
#else
@interface MyAwesomeView : NSView
#endif
{
...
} @end
However UIView
and NSView
have many different API and behaviors:
UIView |
NSView |
---|---|
Receives and handles events | Receives and handles events |
Responsible for drawing | Responsible for drawing |
Always backed by Core Animation | Layer-backed views optional |
Layer Origin in top left | Origin in bottom left |
Subviews can draw outside view bounds | Subviews clip to view bounds |
Gesture Recognizers | Mouse event handling |
Animation APIs | Drag and Drop |
Tooltip support |
Cons:
- Commonly breaks builds
- Hard to target fixes
- Requires
#if TARGET_OS_IPHONE
by design- Hard to read
- Hard to maintain
Behaviors and UI will take on the look of the original (development) platform by default.
- Similar to views, we cannot share view controllers that handle user interactions, hotkeys, mouse handling.
- We can share common controller logic and model controllers:
- split the view controller in various components
- share only what can be shared
-
NSView
has aisFlipped
property that you can use to have the same core graphics coordinates as in iOS (origin on top left corner) -
Create an image wrapper around
UIImage
andNSImage
so that you can grab and share the same CoreGraphics image model on both platforms (accessed viaUIImage
andNSImage
cgImage
property.)- Use this kind of wrappers for just simple objects, not view controllers
As different platforms have different resources available, creating a cross-platform app is also a great opportunity for performance improvements.
Lazily loaded model:
- Make sure that sections of model are self-contained
- Only load what the user needs
- Load in parallel
This kind of gains results in faster opening of documents that benefit all platforms.
Users will not update all apps at the same time, make sure old versions of the app can still open data models created in newer versions, and viceversa.
Create a separate target for each platform.
A target:
- Defines a single product to build
- Organizes inputs into build system
- Is owned by projects (.xcodeproj)
Use libraries for shared code.
Static libraries are:
- Built with the project
- Included as part of the executable
Dynamic libraries are:
- Optionally built with the project (no need to build them again until you change them)
- Excluded from the executable (they're another mach-O file in your app package)
Use Xcode Configuration Files for different targets. See what you can set here in the Build Setting Reference guide.
Used Xcode Configuration inheritance to share common configurations among platforms:
// In the iOS specific .xcconfig
#include "Common.xcconfig"
...