How to have different toggle style for iOS and macOS - swift

I'm trying to have toggle with native style for iOS (switch) and macOS (checkbox) in my universal app. This code does not work:
#if targetEnvironment(macCatalyst)
private let toggleStyle = CheckboxToggleStyle()
#else
private let toggleStyle = SwitchToggleStyle()
#endif
'CheckboxToggleStyle' is unavailable in iOS
Was thinking that macros should compile correct path for each target.

CheckboxToggleStyle is for macOS only... see below API declaration. macCatalyst is actually environment simulating iOS on macOS, but from API perspective it is iOS
/// A `ToggleStyle` represented by a leading checkbox.
#available(OSX 10.15, *)
#available(iOS, unavailable)
#available(tvOS, unavailable)
#available(watchOS, unavailable)
public struct CheckboxToggleStyle : ToggleStyle {

Related

UIBezierPath Not Found On Multi-platform Project

I created a multi-platform game in Xcode and UIBezierPath gives a "Cannot find 'UIBezierPath' in scope" error. I'm sure I'm just missing importing a kit but I don't know which one.
short answer: if you're trying to use UIBezierPath you need to import UIKit
longer note re "multi-platform": your question doesn't provide much context.. but if you mean you started developing a UIBezierPath for iOS, and then switched to a different platform target (ex: macOS), then yes many of your classes won't work. often, but not always, there is simply an equivalent class for macOS that uses the "NS" prefix instead of the "UI" prefix. (NS is a legacy reference to "Next Step"). so try using AppKit classes like NSBezierPath when you target macOS, instead of UIKit classes.
#if os(macOS)
import AppKit
#elseif os(iOS)
import UIKit
#endif
warning: UI/NS classes frequently have different implementation. so it's normal to have different constructors, function calls, etc. meaning you often have to have two implementations in code using the above if/elseif/endif structure. yes this can be tedious.
UPDATE
Here is an example for drawing an ellipse in both macOS and iOS. note: the macOS version uses a CGMutablePath (since there's not a simple way to construct a SKShapeNode from an NSBezierPath on macOS like there is on iOS). if you do want to use NSBezierPath, you might also try these techniques for converting NSBezierPath to CGPath
override func didMove(to view: SKView) {
let rect = CGRect(x: 0, y: 0, width: 200, height: 200)
#if os(macOS)
let path = CGMutablePath(ellipseIn:rect, transform:nil)
let shape = SKShapeNode(path:path)
#elseif os(iOS)
let path = UIBezierPath(ovalIn: rect)
let shape = SKShapeNode(path: path.cgPath)
#endif
addChild(shape)
}

SwiftUI custom accentColor not working on physical device(iOS 13) but works everywhere else(iOS 14.0+)

In my SwiftUI View I've an Image that I've loaded from assets. I've set the foregroundColor to accentColor, which I've also set in asset as my custom AccentColor which is to be used throughout the app.
Asset:
ContentView body:
var body: some View {
Image("MyImageName")
.resizable()
.renderingMode(.template)
.foregroundColor(.accentColor)
.frame(width: 32, height: 32, alignment: .center)
}
The preview and the simulator show the image in the right foregroundColor. But, while running on a physical device the foregroundColor somehow remain the default blue accentColor of the phone.
Preview:
Simulator:
Real Device:
Why does this happen? And how do I make sure the AssentColor work across devices no matter the iOS version without modifying any settings on the iPhone? Debug details: The device iOS version is iOS 13.5.1 and Xcode 12.0.1.
Color.accentColor works fine, even changing it on a View with .accentColor(newColor) works on iOS 13.
The only problem is that iOS 13 doesn't set Color.accentColor to the color in the assets specified by ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME.
What worked for me was to do that step manually by simply setting the window.tintColor to that color:
if #available(iOS 14, *) {} else {
window.tintColor = UIColor(named: "AccentColor")
}
So, while testing further I found that even though accentColor is available from iOS 13.0, customizing accentColor is only available from iOS 14.0. So I created an extension to use the accentColor from asset manually in iOS 13 and work normally in iOS 14.0 and above.
extension Color {
static var accent: Color {
if #available(iOS 14.0, *) {
return accentColor
} else {
return Color(#colorLiteral(red: 0.5, green: 0.5, blue: 0.5, alpha: 1))
}
}
}
I wanted to leave a reminder here that the global app tint color can be broken by accessing properties of the application (including selection color, tint colors, etc) or constructing some views before the application creates the first UIWindow.
If tint color is broken everywhere (including in the simulator) make sure you're not trying to construct or access UIKit components before your first window, including third party SDKs. In my app, a third-party crash logging SDK was breaking the accent color.

Swift if #available not working as expected?

I have a shared framework that runs in both iOS and MacOS, and I've run into a situation where in MacOS Catalina I need to make an extra check. I thought that by using the swift #available this would work:
if #available(OSX 10.15, *){
/// My Catalina Code
}
The truth is that this code passes in iOS. Would this be a bug, or is it not expected to be used this way ?
If you look through Apple documentation it should be like that.
if #available(macOS 10.15, *){
/// My Catalina Code
}
it should look like this:
if #available(macCatalyst 10.15, *) {
// use 10.15
} else {
}
if your using Catalyst.
other than that there is nothing that shows why your code snippet doesn't work.
You may need to use conditional compiling together with #available:
#if os(macOS)
if #available(macOS 15.0, *) {
//...
}
#endif
Or an ugly workaround:
if #available(macOS 15.0, iOS 9999.99, *) {
//...
}

How to detect iOS11 programmatically in Swift?

I saw in the WWDC video that there's some new swift function to detect iOS 11 availability.
How do I detect iOS11 with Swift?
Swift 3:
if #available(iOS 11.0, *) {
// Running iOS 11 OR NEWER
} else {
// Earlier version of iOS
}
More information is available in Declaration Attributes section of Apple's Swift Programming Guide.
Objective C:
if (#available(iOS 11, *)) {
// Running iOS 11 OR NEWER
} else {
// Earlier version of iOS
}

#if Macro in swift to checking device

i am defining the macro at my Appdelegate , here is my code
let IPHONE = UIDevice.currentDevice().userInterfaceIdiom == .Phone
let IPAD = UIDevice.currentDevice().userInterfaceIdiom == .Pad
#if IPHONE
let LEFT_DRAWER_HEIGHT : CGFloat = 270.0
#elseif IPAD
let LEFT_DRAWER_HEIGHT : CGFloat = 404.0
#else
let LEFT_DRAWER_HEIGHT : CGFloat = 404.0
#endif
but it always returns LEFT_DRAWER_HEIGHT = 404.0 rather i have run in iphone device. whats the mistake? can anyone figure it out.
Do you have separate targets for iPhone and iPad? And are you defining those constants in each of those targets?
#if is a compile time conditional, so if you have a universal app, the compiler can't know at compile time what device will the app run on. You should instead use a normal if condition.