What's the difference between a protocol extended from AnyObject and a class-only protocol?
ClassSwiftProtocolsClass Problem Overview
Both this declaration
protocol SomeProtocol : AnyObject {
}
and this declaration
protocol SomeProtocol : class {
}
seem to make it so that only classes can conform to this protocol (i.e. that the instances of the protocol are references to objects), and have no other effects.
Is there any difference between them? Should one be preferred over the other? If not, why is there two ways to do the same thing?
I am using the latest released Xcode 6.3.1.
Class Solutions
Solution 1 - Class
This was answered by an official Swift developer (Slava_Pestov) on the Swift forums. Here is the summary:
-
You should use
AnyObject
(protocol SomeProtocol: AnyObject
). -
AnyObject
andclass
are equivalent. There is no difference. -
class
will eventually be deprecated.
Solution 2 - Class
Regarding the answer https://forums.swift.org/t/class-only-protocols-class-vs-anyobject/11507/4, this answer is deprecated. These words are the same now.
DEPRECATED
Update: After consulting with the powers that be, the two definitions are supposed to be equivalent, with AnyObject
being used as a stand-in while class
was being finished. In the future the latter will obviate the former but, for now, they do present a few minor differences.
The difference lies in the semantics of @objc
declarations. With AnyObject
, the expectation is that conforming classes may or may not be proper Objective-C objects, but the language treats them as such anyway (in that you lose static dispatch sometimes). The takeaway from this is that you can treat an AnyObject
et al. protocol constraint as a way to ask for @objc
member functions as shown in the example in documentation for AnyObject
in the STL:
import Foundation
class C {
@objc func getCValue() -> Int { return 42 }
}
// If x has a method @objc getValue()->Int, call it and
// return the result. Otherwise, return nil.
func getCValue1(x: AnyObject) -> Int? {
if let f: ()->Int = x.getCValue { // <===
return f()
}
return nil
}
// A more idiomatic implementation using "optional chaining"
func getCValue2(x: AnyObject) -> Int? {
return x.getCValue?() // <===
}
// An implementation that assumes the required method is present
func getCValue3(x: AnyObject) -> Int { // <===
return x.getCValue() // x.getCValue is implicitly unwrapped. // <===
}
The same example falls over immediately if you change that to a class
-deriving protocol:
import Foundation
protocol SomeClass : class {}
class C : SomeClass {
@objc func getCValue() -> Int { return 42 }
}
// If x has a method @objc getValue()->Int, call it and
// return the result. Otherwise, return nil.
func getCValue1(x: SomeClass) -> Int? {
if let f: ()->Int = x.getCValue { // <=== SomeClass has no member 'getCValue'
return f()
}
return nil
}
// A more idiomatic implementation using "optional chaining"
func getCValue2(x: SomeClass) -> Int? {
return x.getCValue?() // <=== SomeClass has no member 'getCValue'
}
// An implementation that assumes the required method is present
func getCValue3(x: SomeClass) -> Int { // <===
return x.getCValue() // <=== SomeClass has no member 'getCValue'
}
So it seems class
is a more conservative version of AnyObject
that should be used when you only care about reference semantics and not about dynamic member lookups or Objective-C bridging.
Solution 3 - Class
In the Swift programming language guide for protocols, under the Class-Only Protocols section. It only mentioned AnyObject
, but not class
.
> You can limit protocol adoption to class types (and not structures or enumerations) by adding the AnyObject protocol to a protocol’s inheritance list.
protocol SomeClassOnlyProtocol: AnyObject, SomeInheritedProtocol {
// class-only protocol definition goes here
}
For that reason, I will suggest using AnyObject
over class
for new code or new project. Other than that, I don't see any obvious difference between them.
Solution 4 - Class
AnyObject
is a protocol to which all classes implicitly conform (source). So I would say there is no difference: you can use either to require class constraint.
Solution 5 - Class
From 2021, Xcode 12.5, Big Sur OS:
Usage of class
is deprecated by apple.
Use AnyObject
instead.
Happy Coding.
Solution 6 - Class
If you open the help (alt-click) in Xcode 9 for class
in a line such as protocol P: class {}
, you will get typealias AnyObject
.
Thus, the code compiled (in Swift 4) will be the same whether you constrain the protocol to class
or AnyObject
.
That said, there is also the question of style and future options — a future Swift version might want to treat class
and AnyObject
differently in some subtle way, even if that is not the case right now.
(Edit: This has finally happened in Swift 5.4/Xcode 12.5.)
Solution 7 - Class
I misspoke before. @MartinR should really answer this, since he's the one who corrected me and provided the correct information.
The real difference is that a protocol with the class qualifier can only be applied to a class, not a struct or enum.
Martin, why don't you answer and the OP can accept your answer?