Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Protocols: Why is @ObjC required for conformance checking and optional requirements?

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]")
    }
}
like image 282
Ricardo Sanchez-Saez Avatar asked Nov 13 '14 13:11

Ricardo Sanchez-Saez


People also ask

How do I declare Optional protocol in Swift?

To define Optional Protocol in swift you should use @objc keyword before Protocol declaration and attribute / method declaration inside that protocol.

How do you conform to a protocol in Objective-C?

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.

How do you ensure the adoption of a protocol only by reference type?

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.

What is the difference between Swift protocol and Objective-C protocol?

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.


2 Answers

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.

like image 153
Ricardo Sanchez-Saez Avatar answered Oct 06 '22 19:10

Ricardo Sanchez-Saez


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:").

like image 28
uliwitness Avatar answered Oct 06 '22 19:10

uliwitness