I am using #available to prevent some functions to be called at certain OS versions. Lets say I have two functions and both should be restricted to macOS version 12 and below. Not available at macOS 13. Hence I want to write
#available(macOS, obsoleted: 12)
extension MyStruct {
func myFunc1() -> String { ... }
func myFunc2() {
let resultOfCallOfMyFunc1 = myFunc1()
}
}
I thought that this way both functions are only available at the same platfroms. But I am getting error, when I try to use myFunc1 in myFunc2 why is that?
The error is: "myFunc1()" is unavailable in macOS
I also tried to mark each function separately instead of marking the whole extension, but no luck there either.
Any reason why this fails? How to use #available the way, that I will be able to use one function inside another one?
According to the Language Reference, obsoleted indicates the first version in which the member is unavailable.
The obsoleted argument indicates the first version of the specified platform or language in which the declaration was obsoleted.
So you should write obsoleted: 13 instead. obsolete: 12 would mean that the extension is obsolete since macOS 12. Assuming that your minimum deployment target is equal to or higher than macOS 12, this would mean that the extension is obsolete on all the possible devices your app will be installed on, hence "myFunc1 is unavailable".
Note that the obsolete argument prevents code that targets higher OS versions from compiling. It is still possible to compile code targeting a lower version, and run myFunc1 on macOS 13+. If you don't want myFunc1 to execute at all on macOS 13+ at all. You should use an #unavailable check:
if #unavailable(macOS 13, *) {
let resultOfCallOfMyFunc1 = myFunc1()
}
Related
I am using the Cocoapod Money (version 2.0.1). When I try to build it, I get the error "Type _Decimal does not conform to protocol 'Numeric'" Any ideas as to how to fix it?
I've already tried removing and reinstalling the cocoapod.
Thanks,
Sounds like you’re using a Numeric number while the pod wants an decimal number. Just try to cast your numeric in decimal and it should work.
According to the pod's .swift-version it is written in Swift 3. My guess is that the build error results from a conflict in Swift versions with the current Xcode. The project is no longer maintained but according to this issue there is a branch which should make it buildable on Xcode 9.
I've got a project written in Swift 3 that has a number of #if ... #elses scattered throughout; they just check for a certain variable (defined with the -D compiler flag) which is set by my xcode project to know if the project is being built in xcode or with the package manager and does some imports accordingly. For example,
#if XCODE_BUILD
// do some imports that work when built with xcode
#else
// do some imports that won't work when built with xcode
#endif
The code builds just fine via either method.
But, when I select the option to upgrade to Swift 4 (either of the options offered -- "Minimize inference" or "Match Swift 3 behavior"), the code fails to compile so the migration fails. It appears that the #ifs are not being respected or the XCODE_BUILD variable isn't being defined, since the failures occur in the imports that shouldn't happen when being built from Xcode.
Does Swift 4 do something different with #ifs? Does Xcode somehow not define the compiler flags while doing the migration?
You can use #if, #else and #endif, resulting in:
#if XCODE_BUILD
// do some imports that work when built with xcode
#else
// do some imports that won't work when built with xcode
#endif
Apple docs here.
Another answer with some additional details can be found here: https://stackoverflow.com/a/24152730/118091
Previously, I was using the 'Other Swift Flags' build setting in Xcode to pass '-DXCODE_BUILD'. Apparently that setting doesn't work for Swift 4. The new setting that does work is 'Active Compilation Conditions' (it should be set to include XCODE_BUILD, no need for the -D flag).
I'm currently starting up work on a project, and my first task is decomposing a God Object that someone else created out of the AppDelegate. I've started by copying code related around managing location out, in the intention of delegating calls to that code into the new object.
I have two statements that are driving me nuts however.
New file:
if locationManager?.location?.horizontalAccuracy > horizontalAccuracyCheck{...}
Old file:
if locationManager?.location?.horizontalAccuracy > horizontalAccuracyCheck{...}
You'll notice the code is identical. In both cases self.locationManager? is defined as:
var locationManager: CLLocationManager?
But in the new file, I'm getting a warning about 'value of optional type no unwrapped' -- why? Exact duplicate code, copied & pasted, what would make this different?
Changing the code to unwrap it fixes things:
if (locationManager?.location?.horizontalAccuracy)! > horizontalAccuracyCheck{...}
I can wrap my head around why I need to explicitly unwrap a potentially optional return. But... why only in one place?
The reason is that we're talking here about two quite different languages. One file is Swift 2, the other file is Swift 3.
In Swift 2, you can compare an Optional representing a number with another number using the greater-than or less-than operator. In Swift 3, you can't do that.
Here's a simpler example of the same thing:
let optint : Int? = 7
let ok = optint < 42
That code is legal in Swift 2 but illegal in Swift 3.
As discussed in this Q&A – the Swift migrator will insert a custom fileprivate operator overload in order to allow for optional comparisons to work in Swift 3 the same way they did in Swift 2. Because this overload is fileprivate, you won't be able to use it from any other source files in your project that don't also define it, thus why your comparison fails to compile in the new source file.
Therefore one solution is just to copy it over to your new file. Another is to remove the fileprivate access modifer. The overload will default to internal, and therefore be accessible to other Swift files in your module.
Although really I would just recommend removing the overload entirely and instead write your own explicit logic for optional comparison when it arises – the overload can be too easily misused (as demonstrated by the Swift evolution proposal to remove it).
I'm using Appcode-EAP 3.2, but I've also tried this with Appcode 3.1.7.
When stopped in the debugger, I can see the local variables,
e.g.
fromJSON = []
self = []
However, if I move one of these to the Watches window to examine its contents, I get this:
self = Cannot evaluate expression for language Swift
I can't believe it isn't possible to see the values of a variable or property. Can anyone guide me as to what I'm failing to do?
Current AppCode versions (stable 3.1 and 3.2 EAP) don't support Swift debugging. It should be included into the final 3.2 release however: https://youtrack.jetbrains.com/issue/OC-11626
I am running into a weird issue when trying to test for the existence of a symbol that is introduced in a newer version of the OS. I follow the Apple guidelines on using weak-linked symbols, i.e.
Check the availability of an external (extern) constant or a
notification name by explicitly comparing its address—and not the
symbol’s bare name—to NULL or nil.
To reproduce the issue, I am using the latest iOS 6 SDK on the latest Xcode 4.5.2, using the default compiler (Apple LLVM compiler 4.1). I weak-linked the Social framework (which is only available on iOS 6+). And I run this code on iOS 5.1 (the deployment target is lower than 6):
NSLog(#"%p", &SLServiceTypeFacebook);
if (&SLServiceTypeFacebook)
NSLog(#"Yes1");
if (&SLServiceTypeFacebook != NULL)
NSLog(#"Yes2");
The output is:
0x0
Yes1
Yes2
In other words, we can verify at runtime that the expression &SLServiceTypeFacebook evaluates to the value 0. Yet, if statements that test on this expression treat it as if it is true.
Update:
From this question, I found that this workaround works with no optimization, but not with optimization:
typeof(&SLServiceTypeFacebook) foo = &SLServiceTypeFacebook;
if (foo)
NSLog(#"Yes3"); // does not get executed on -O0, but does on any optimization
Update:
It appears that this problem does not exist with UIKit symbols. Running the following on iOS 4.3:
NSLog(#"%p", &UIKeyboardDidChangeFrameNotification);
if (&SLServiceTypeFacebook)
NSLog(#"Yes1");
if (&SLServiceTypeFacebook != NULL)
NSLog(#"Yes2");
The output is:
0x0
I hypothesize that the difference is that the UIKit symbol has a NS_AVAILABLE_IOS() macro next to it, so somehow the compiler handles it correctly. In the case of the Social framework symbol, it doesn't have a NS_AVAILABLE_IOS() macro since the entire Social framework itself is only available since iOS 6 (i.e. the symbol is available since the version of the framework, so I guess the don't need this macro?); but then the compiler does not handle the symbol correctly.
Are you sure you don't want to check that the SLRequest class exists instead of checking for this constant?
In any case, the issue is that the compiler is optimizing the test away (it interprets this as testing a constant expression which is true at compile time). You can circumvent this by reading this address into a local volatile variable. Or you could dynamically search for the symbol at runtime.
But I would consider just checking for the SLRequest class instead.
Here are at least these three options:
#include <dlfcn.h>
NSString* const * volatile check = &SLServiceTypeFacebook;
if (check != NULL)
NSLog(#"SLServiceTypeFacebook is defined");
// Another approach would be to call dlsym() at runtime
// to search for this symbol:
if (dlsym(RTLD_DEFAULT, "SLServiceTypeFacebook"))
NSLog(#"SLServiceTypeFacebook found via dlsym");
// But if you really just wanted to know is if SLRequest
// is available, you should really just do this:
if ([SLRequest class])
NSLog(#"SLRequest class is available");
Any of these should work as you were expecting in iOS5.1 versus iOS6.
just check with NSClassFromString if you can get the classes.. objC is all classes anyway :D