The Swift documentation says the following about protocols:
You can check for protocol conformance only if your protocol is marked with the @objc attribute, as seen for the HasArea protocol above. This attribute indicates that the protocol should be exposed to Objective-C code and is described in Using Swift with Cocoa and Objective-C. Even if you are not interoperating with Objective-C, you need to mark your protocols with the @objc attribute if you want to be able to check for protocol conformance.
Note also that @objc protocols can be adopted only by classes, and not by structures or enumerations. If you mark your protocol as @objc in order to check for conformance, you will be able to apply that protocol only to class types.
and
Optional protocol requirements can only be specified if your protocol is marked with the @objc attribute. Even if you are not interoperating with Objective-C, you need to mark your protocols with the @objc attribute if you want to specify optional requirements.
Note also that @objc protocols can be adopted only by classes, and not by structures or enumerations. If you mark your protocol as @objc in order to specify optional requirements, you will only be able to apply that protocol to class types.
Why cannot pure Swift protocols (non-@objc
) be checked for conformance. Why don't they have optional requirements? Can anybody guess the underlying language design reason?
I expect that at some undetermined (probably far away) time in the future Apple will slowly reimplement and replace Cocoa and CocoaTouch with libraries programmed purely in Swift. At that time, if we wan't to avoid using any Obj-C related stuff, should we avoid using optional protocol requirements and protocol checks conformance in our code?
If so, what's Swift's idiomatic way of achieving similar patterns without using @objc
? (E.g., a delegate with optional methods.)
For example, this simple use case cannot be implemented with non-@objc
protocols (and Printable
, DebugPrintable
and Streamable
are non-@objc
:
import UIKit
let firstName = "John"
let lastName = "Appleseed"
let age = 33
let height = 1.74
let values: [Any] = [firstName, lastName, age, height]
let stringifiedValues = [String]()
for value in values
{
if let pritanbleValue = value as? Printable
{
stringifiedValues.append(value.description)
}
else if let debugPrintableValue = value as? DebugPrintable
{
stringifiedValues.append(value.debugDescription)
}
else if let streamableValue = value as? Streamable
{
var string = ""
streamableValue.writeTo(&string)
stringifiedValues.append(string)
}
// etc.
else
{
stringifiedValues.append("[NoStringRepresentation]")
}
}
To define Optional Protocol in swift you should use @objc keyword before Protocol declaration and attribute / method declaration inside that protocol.
Objective-C uses angle brackets to indicate conformance to a protocol. This example declares a weak property for a generic object pointer that conforms to the XYZPieChartViewDataSource protocol.
You can limit protocol adoption to class types (and not structures or enumerations) by adding the AnyObject or class protocol to a protocol's inheritance list.
In Objective-C, protocols are declared with the “@protocol” keyword. Below is an example of declaring a protocol containing one required method. In Swift, the syntax is a little different but the idea is the same. In Objective-C, you add the protocol name in angle brackets beside the class interface declaration.
jckarter, an Apple employee, said the following on an Apple Developer Forums' thread:
This is a limitation of Swift's runtime. We intend to remove this restriction in a future release.
Swift probably does not include enough runtime type information to check for protocol conformance. Protocols are really only a compile-time thing, and ObjC includes extra tables in the built product that aren't strictly necessary for running the program to allow determining conformance. Since @objc has to turn a class/protocol into something that ObjC understands, objects declared with this attribute get the additional metadata and probably other adapter data structures so ObjC won't notice they're not real ObjC.
The recommendation from Apple in ObjC has always been to check for the presence of individual methods, and not to look at the class or protocol, to permit duck typing and enable use of proxy objects. My guess is that this is the reason why the designers of Swift felt it was OK to leave out protocol runtime data in the default case, to encourage proper detection of features of a class.
As to how to use it: For the case of a protocol you're apparently supposed to use the ?
operator (which checks both whether the object exists and that it implements the given method). I don't know if the same works for system API, but given it's an ObjC class in that case, you can just call foo.respondsToSelector("doFoo:")
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With