I have a multiplatform SwiftUI app which uses a custom view that is platform-specific in that it derives from NSView on macOS and UIView on iOS. These are legacy classes written in Objective-C & I'd like to use them in my SwiftUI app.
The ContentView
presented by the app looks like,
struct ContentView: View {
var body: some View {
VStack {
Image(systemName: "globe")
.imageScale(.large)
.foregroundColor(.accentColor)
Text("Hello, world!")
CustomViewWrapper()
.border(.yellow)
}
.padding()
}
}
This wrapper CustomViewWrapper
is platform-specific:
#if os(iOS)
struct CustomViewWrapper : UIViewRepresentable {
func makeUIView(context: Context) -> UIView {
CustomView()
}
func updateUIView(_ uiView: UIView, context: Context) {
// TODO
}
}
#else
struct CustomViewWrapper : NSViewRepresentable {
func makeNSView(context: Context) -> NSView {
CustomView()
}
func updateNSView(_ nsView: NSView, context: Context) {
// TODO
}
}
#endif
The custom view is in its Objective-C file CustomView.h
,
#if TARGET_OS_IPHONE == 0
#include <AppKit/AppKit.h>
@interface CustomView : NSView
@end
#else
#include <UIKit/UIKit.h>
@interface CustomView : UIView
@end
#endif
with its implementation in the corresponding CustomView.m
file. This header is exposed to the Swift code via a bridging header. The problem is that the macro #if TARGET_OS_IPHONE == 0
always resolves to true and the code goes down the AppKit root on iOS too. The compiler throws an error about the unavailability of AppKit on iOS. On macOS, it compiles fine.
Question: what macro can I use to separate code destined for macOS and iOS in my Objective-C files when I'm in a single, multiplatform SwiftUI target? Or do I have to create two separate targets, one for macOS and one for iOS, and include files with AppKit views in the macOS target and files with UIKit views in the iOS target?
Note that if I replace my CustomView()
above in NSViewRepresentable
and UIViewRepresentable
wrappers with simple NSView()
and UIView()
respectively,
...
func makeUIView(context: Context) -> UIView {
UIView()
}
...
and
func makeNSView(context: Context) -> NSView {
NSView()
}
it all works fine and the the views render on both macOS and iOS without any problems. This can be seen in the attached screenshots where the border is being provided by .border()
in SwiftUI.