In Swift, What Does It Mean for Protocol to Inherit from Class Keyword

In Swift, what does it mean for protocol to inherit from class keyword?

The gist of Starscream's answer is correct, but it misses the why which I think is important here. It comes down to ARC and memory management.

Swift is a language of reference types and value types. Classes are reference types, while everything else is a value type. Effectively, we're not really specifying that the protocol inherits from class... it's more like we're specifying that the protocol can only be implemented by reference types.

And why is that important?

It's important, because without it, we can't use the weak keyword with the protocol.

protocol ExampleProtocol {}

class DelegatedClass {
weak var delegate: ExampleProtocol?
}

This generates the error:

'weak' cannot be applied to non-class type 'ExampleProtocol'

Sample Image

And why not? Because the weak keyword only makes sense with reference types to which ARC applies. ARC does not apply to value types. And without specifying our protocol with class, we cannot guarantee that our delegate property is set to a reference-type. (And if we don't use weak, we're most likely creating a retain cycle.)

What exactly does `: class` do in a protocol declaration?

:class ensures that only classes can implement the protocol. And that's any class, not just subclasses of NSObject. @objc, on the other hand, tells the compiler to use Objective-C-style message passing to call methods, instead of using a vtable to look up functions.

Why do Swift Class-Only Protocols need AnyObject Inheritance?

When you write a protocol, you define an interface for the types which adopt, or conform to the protocol:

// Every Greeter has a greeting message
// and a way for it to present that message.
protocol Greeter {
var greeting: String { get }
func greet()
}

extension Greeter {
// Default implementation for the `greet` method.
func greet() {
print(self.greeting)
}
}

This gives consistent behavior to every type which conforms and lets you treat them all in the same way regardless of what they are. For instance, a type can store a value bound to a protocol type:

struct Store {
// The name of the store.
var name: String

// The address of the store.
var address: String

// An entity that greets customers when they walk in.
var greeter: Greeter
}

In this case, Store.greeter can be set to any value or object which conforms to the Greeter protocol:

struct Bell: Greeter {
let greeting = "Ding!"
}

class Person: Greeter {
let greeting: String

init(name: String) {
greeting = "Welcome! My name is \(name)."
}
}

var store = Store(name: "My Shop", address: "123 Main St.", greeter: Bell())
store.greeter.greet() // => "Ding!"

store.greeter = Person(name: "Itai")
store.greeter.greet() // => "Welcome! My name is Itai."

By default, a protocol can be adopted by both value types and object types, i.e., both structs and classes. This is a good default because in many cases, there's no reason to restrict who can conform to a protocol.

However, there is one case where this matters. By default, Store owns its greeter property, i.e., when you assign an object to store.greeter, it is retained. This is normally fine, except when you have a potentially circular relationship (for example, if Person has a reference to the Store they work at).

Normally, to break a potential circular chain like this up, you would make the variable weak:

struct Store {
// ...
weak var greeter: Greeter?
// ^ error: 'weak' must not be applied to non-class-bound 'Greeter'; consider adding a protocol conformance that has a class bound
}

If you try this, though, you'll get the above error. This is because weak only makes sense for objects, not for structs (structs can only be owned because they are value types — every owner just makes a copy of a struct, so there is no one central value to retain or release). In this case, to ensure a weak reference, you must ensure that Greeter an only be an object type.

The way to do this is to constrain the protocol to only allow classes to conform by using AnyObject as a constraint:

protocol Greeter: AnyObject {
// ...
}

Now, Bell can't conform to Greeter any more (error: non-class type 'Bell' cannot conform to class protocol 'Greeter') but you are allowed to have weak var greeter: Greeter? as a variable.


So, when should you restrict your protocol to be "class-bound" (using AnyObject)? Well, only when you really have to. The one benefit for class-bound protocols is to allow weak references to them, and the main use-case for that is with delegate references to prevent circular retains.

For instance, UITableView has a weak delegate property because the delegate object is usually the view controller which owns the UITableView object itself. If the view controller retains the table view, and the table view retains the controller, neither can be released automatically.

So, in the general case, you don't need to worry about the AnyObject constraint unless you really do only want classes to conform to the protocol.

Swift -- Require classes implementing protocol to be subclasses of a certain class

I think you are after a subclass of NSView. Try this:

protocol TransmogrifiableView {
func transmogrify()
}

class MyNSView: NSView, TransmogrifiableView {
// do stuff.
}

And later in the code accept objects of type MyNSView.

Edit

You maybe want an Extension, see this

extension NSView: TransmogrifiableView {
// implementation of protocol requirements goes here
}
  • Note that you will not be able to get an NSView without this extra method.
  • You can separately extend subclasses of NSView to override this new method.

Yet another option is to make a class which holds a pointer to an NSView, and implements additional methods. This will also force you to proxy all methods from NSView that you want to use.

class NSViewWrapper: TransmogrifiableView {
var view : NSView!
// init with the view required.
// implementation of protocol requirements goes here.
.....
// proxy all methods from NSView.
func getSuperView(){
return self.view.superView
}
}

This is quite long and not nice, but will work. I would recommend you to use this only if you really cannot work with extensions (because you need NSViews without the extra method).

Swift Protocol inheriting Protocol method with same name

This is because a non-throwing function is by definition a sub-type of a throwing function

From the Swift Programming Language book

The throws keyword is part of a function’s type, and nonthrowing functions are subtypes of throwing functions. As a result, you can use a nonthrowing function in the same places as a throwing one.

But you can't do it the other way around so the below code will generate an error

protocol Base {
func foo() -> Int
}

protocol Refined: Base {
func foo() throws -> Int //error: Cannot override non-throwing method with throwing method
}

Also note that this is not only for protocols, if you remove the func declaration from Refined you can still implement the function in Test as non throwing.



Related Topics



Leave a reply



Submit