Swift: Property Conforming to a Specific Class and in the Same Time to Multiple Protocols

Swift: Property conforming to a specific class and in the same time to multiple protocols

You can do this with a generic class using a where clause:

A where clause enables you to require that an associated type conforms
to a certain protocol, and/or that certain type parameters and
associated types be the same.

To use it, make the class your property is defined in a generic class with a type constraint to check if the type parameter for your property matches your desired base class and protocols.

For your specific example, it could look something like this:

class MyViewController<T where T: UIView, T: Protocol1, T: Protocol2>: UIViewController {
var myView: T

// ...
}

Swift: Array property with elements conforming to a class and multiple protocols simultaneously

I just came across this old question of mine and because the Swift language evolved since accepting the partial answer I decided to post another answer which actually solves the problem I originally asked.

From version 4, Swift supports protocol composition using the & sign which can also be composed with one class type.

class BaseClass {}
protocol Protocol1 {}
protocol Protocol2 {}

class ConformingClass1: BaseClass, Protocol1, Protocol2 {}
class ConformingClass2: BaseClass, Protocol1, Protocol2 {}

// It works for a variable holding a single object.
let object: BaseClass & Protocol1 & Protocol2 = ConformingClass1()

// And it also works for a variable holding an array of objects.
let array: [BaseClass & Protocol1 & Protocol2] = [ConformingClass1(), ConformingClass2()]

Swift class conformance of multiple protocols (XCode 7, iOS 9, Swift 2.1)

You have to implments the protocol function in the class

For example

protocol Protocol_A {
func someFunc()
}

protocol Protocol_B {
func someFuncB()
}

protocol Protocol_C {
}

protocol Protocol_D {
}


class ViewController: UIViewController, Protocol_A, Protocol_B, Protocol_C, Protocol_D {
func someFunc() {

}
func someFuncB() {

}
}

If you want function to be optional

@objc protocol Protocol_A {
optional func someFunc()
}

var defined in protocol doesn't conform to multiple protocol

You have two issues: firstly, the property name must match that declared in the protocol, secondly you need to type annotate the variable to be of type BProtocol as Hamish explained in the comment.

protocol AProtocol {
var aProperty : BProtocol {get set}
}

protocol BProtocol {}
class BClass: BProtocol {}

class AClass: AProtocol {
var aProperty: BProtocol = BClass()
}

You should also conform to the Swift naming convention, which is lowerCamelCase for variable names, so I changed AProperty to its correct form, aProperty.

Swift: Make two types with the same shape conform to a common protocol

The name properties of the generated structs have type Name, not NameRepresenting as required by the protocol. Covariant returns are not supported in Swift just yet :(

What you can do is to add an associated type requirement:

protocol UserRepresenting {
associatedtype Name : NameRepresenting
var email: String { get }
var name: Name { get }
}

This requires that the conformers to have a type that conforms to NameRepresenting and is the type of the name property.

However, now that it has an associated type requirement, you cannot use UserRepresenting as the type of a variable/function parameter. You can only use it in generic constraints. So if you have a function that takes a UserRepresenting, you need to write it like this:

func someFunction<UserType: UserRepresenting>(user: UserType) {

}

and if one of your classes/structs need to store a property of type UserRepresenting, you need to make your class/struct generic too:

class Foo<UserType: UserRepresenting> {
var someUser: UserType?
}

This may or may not work for your situation. If it doesn't, you can write a type eraser:

struct AnyUserRepresenting : UserRepresenting {
var email: String
var name: Name
struct Name : NameRepresenting {
var givenName: String
var familyName: String
}

init<UserType: UserRepresenting>(_ userRepresenting: UserType) {
self.name = Name(
givenName: userRepresenting.name.givenName,
familyName: userRepresenting.name.familyName)
self.email = userRepresenting.email
}
}

Now you can convert any UserRepresenting to this AnyUserRepresenting, and work with AnyUserRepresenting instead.

Implement a public method that rely on a private property in Swift using protocols

Following this discussion from Swift forum, there are two ways to solve the issue.

First one is straightforward:

/// The publically visible capabilities.
public protocol SameModifierProtocol {
func modifier(x: Int) -> SameModifierProtocol
}
/// The internal requirements on which the default implementation relies.
internal protocol SynthesizedSameModifierProtocolConformance:
SameModifierProtocol {
var x: Int { get set }
}
/// The default implementation.
extension SynthesizedSameModifierProtocolConformance {
public func modifier(x: Int) -> SameModifierProtocol{
var s = self
s.x = x
return s
}
}

/// Conforms to the public protocol
/// and requests the default implementation from the internal one.
/// Clients can only see the public protocol.
public struct Component: SynthesizedSameModifierProtocolConformance {
internal var x: Int = 0
public init() {}
}

The second involves an unofficial feature @_spi, that allows to make implementation details unexposed in a public protocol:

public protocol SameModifierProtocol {
@_spi(SameModifier) var x: Int { get set }
}

extension SameModifierProtocol {
public func modifier(x: Int) -> Self {
var s = self
s.x = x
return s
}
}

public struct Component: SameModifierProtocol {
@_spi(SameModifier) public var x: Int = 0
public init() {}
}

How to declare a property of a particular class which is also protocol conformant?

Answering my own question 3 years later, Swift 4 supports combined class and protocol types:

let delegate: UIViewController & MyDelegateProtocol


Related Topics



Leave a reply



Submit