How to use @available attribute in Swift
Today I am going to write about attributes that Swift offers. Attribute is nothing but the construct which provides more information about declaration or type. As long as this blog post is concerned, I am going to keep the content specific to Declaration Attributes.
Attributes can be specified with @
symbol followed by attribute name and arguments. Arguments are specific only to certain attributes
For example,
@available(<attribute_name>)
@available(<attribute_name>)(<arguments>)
@available
Declaration attributes can only be applied to declarations. For example available
is a declaration attribute which can be used to specify the Swift language version, platform or iOS version to which declaration belongs.
This attribute can be specified with two or more argument separated by comma. Argument list begins with one of the following platform names or language
- iOS
- iOSApplicationExtension
- macOS
- macOSApplicationExtension
- watchOS
- watchOSApplicationExtension
- tvOS
- tvOSApplicationExtension
- swift
There is one distinction on how these two arguments can be used. If you specify asterisk (*
) for platform names, it means declaration applied to all the platforms. However, you cannot generalize the Swift version specification with just *
. You specifically have to mention the Swift version to which it applies.
@available(iOS 9, *)
func methodWhichUsesStackView() {
}
// Alternatively multiple OS versions
@available(iOS 9, macOS 10.10, *)
Not exactly related to this post, but you can also use attribute
is you don't want to apply attribute to whole method
if #available(iOS 9, *) {
// Use Native StackView
} else {
// Use Third party library which mimics UIStackView
}
// For multiple platforms
#available(iOS 9, macOS 10.10, *)
Please remember to always end this list with
*
to encompass rest of the attributes even if your application is not targeting them
As mentioned earlier in post, you can also specify the Swift version to which the declaration applies
One caveat though, if you want to specify Swift version it can not go with platform availability attribute. Instead, you will have to specify two attributes on each line. One for Swift version and other for platform specification
@available(swift 3.0.2)
struct Swift3SpecificStruct {
}
// In combination with platform specification
@available(swift 3.0.2)
@available(iOS 9, macOS 10.11, *)
struct Swift3SpecificStruct {
}
Other arguments associated with @available
attribute
unavailable
This can be used to specify if code is unavailable on certain platform or not. If specified a platform, construct or code cannot be used when that target is selected.
Message argument is optional, this can be used to hint the user to use alternative construct. Using message argument is highly recommended to make code more readable.
@available(macOS, unavailable, message: "We removed this class from Mac OS recently")
class iOSAvailable {
}
// OR
@available(iOS, unavailable, message: "We removed this class from iOS recently")
class macOSAvailable {
}
obsoleted
and deprecated
Obsolete is used to make code unavailable and deprecated is just to raise warning that code is deprecated
// If you want code to be obsolete on iOS 9.1 and deprecated on 10.1
@available(iOS, deprecated: 10.1, obsoleted: 9.1, message: "API is deprecated in iOS 10.1 and obsoleted in 9.1")
class Available {
}
introduced
This argument specifies the language or version in which the routine was introduced. You cannot use the routine before introduced version number.
// Only available in targets pointing to iOS versions greater than 10.1
@available(iOS, introduced: 10.1)
class Available {
}
@discardableResult
Swift compiler usually throws warning when the result of method or function that returns value is unused.
For example,
func doIt() -> Int {
return 100
}
// Following code will generate warning since result of method call doIt is unused
doIt()
// Following is one of the ways to suppress this warning without using @discardableResult attribute
_ = doIt()
Below is the way to use @discardableResult
in order to suppress the warning generated by unused value returned by method returning value
@discardableResult func doIt() -> Int {
return 100
}
// Below code will not generate any warning since we have used @discardableResult attribute
doIt()
@testable
This attribute is used when you want to import certain modules in your test class for unit testing. In general method and attributes declared as internal
won't be available outside the module. However there are cases such as unit testing where constructs declared with internal
need to be used outside the declared module.
However, if constructs are declared with more strict access modifiers (e.g.
FilePrivate
,Private
) they won't be available outside the module
@testable import MyAwesomeApp
// All the internal method and properties declared inside MyAwesomeApp will be available to unit test
class AwesomeAppTests: XCTestCase {
func testFunctionality() {
// Testing code
}
}
@objc
This attribute is used when constructs (classes, non-generic enums, protocols) in Swift are needed to be made available in Objective-C code. Classes that are marked with @objc
need to be inherited from NSObject
. Also, compiler automatically applies @objc
attribute to any class that inherits from class marked with attribute @objc
.
Also, protocols marked with @objc
cannot inherit from protocols without @objc
. Enums marked with this attribute can also be used in Objective-C code. However, for enums converted from Swift to Objective-C enum type and name are concatenated.
// Swift class can be used in Objective-C
@objc
class swfitClass: NSObject {
}
// Case can be used in Objective-C
@objc
enum Vehicle {
case Car
case Bike
}
// Above enum becomes VehicleCar and VehicleBike when used in Objective-C
@nonobjc
This attribute is used to make construct unavailable in Objective-C. It overrides any previous @objc
declaration applied to construct.
Additionally, to quote Apple:
You use the nonobjc attribute to resolve circularity for bridging methods in a class marked with the objc attribute, and to allow overloading of methods and initializers in a class marked with the objc attribute
One major connection between @nonobjc
and @objc
methods is that methods marked with @nonobjc
cannot override methods marked with @objc
, while methods marked with @objc
can override methods marked with @nonobjc
.
Summary:
-
You can specify the declaration’s availability on different platforms and versions of Swift on the single line
-
The declaration that the available attribute applies to is ignored if the attribute specifies a platform or language version that doesn’t match the current target
-
If you use multiple available attributes, the effective availability is the combination of the platform and available Swift versions
References: