Class-only protocol as typealias for associatedtype with AnyObject constraints - swift

In Swift 4.0 I could write something like this
protocol ObserversHolder {
///Compiling Error in Swift 4.1
///note: possibly intended match 'StringManager.ObserverValue' (aka 'StringObserver') does not conform to 'AnyObject'
///note: protocol requires nested type 'ObserverValue'; do you want to add it?
associatedtype ObserverValue: AnyObject
var observers: [ObserverValue] {get set}
}
protocol StringObserver: class {
func showString()
}
class StringManager: ObserversHolder {
typealias ObserverValue = StringObserver
var observers = [ObserverValue]()
}
But in Swift 4.1 I receive the error Type 'StringManager' does not conform to protocol 'ObserversHolder'.
Is it possible to resolve this?

Change AnyObject to Any
protocol ObserversHolder {
///Compiling Error in Swift 4.1
///note: possibly intended match 'StringManager.ObserverValue' (aka 'StringObserver') does not conform to 'AnyObject'
///note: protocol requires nested type 'ObserverValue'; do you want to add it?
associatedtype ObserverValue: Any
var observers: [ObserverValue] {get set}
}
protocol StringObserver: class {
func showString()
}
class StringManager: ObserversHolder {
typealias ObserverValue = StringObserver
var observers = [ObserverValue]()
}

Related

Protocol restriction on another protocol associated type

I have a protocol MyProtocol which has an associatedtype, inferred by the return type of myFunction
struct MyStruct: Codable {
var myVar: Int
}
protocol MyProtocol {
associatedtype MyType
func myFunction()-> MyType
}
class MyClass1: MyProtocol {
func myFunction()-> MyStruct? {
return MyStruct(myVar: 1) //ex.
}
}
class MyClass2: MyProtocol {
func myFunction()-> Int? {
return 1 // ex.
}
}
In MyClass1, associatedtype is infered as MyStruct?
In MyClass2, associatedtype is infered as Int?
from there everything works fine. No I want to build another protocol that can only be applied to a MyProtocol if associatedtype is Codable :
protocol MyProtocolCodable where Self: MyProtocol, MyType == Codable? {}
the code runs fine until here but when I try to apply it to my class I get an error:
extension MyClass1: MyProtocolCodable{} 🛑
'MyProtocolCodable' requires the types 'MyStruct?' and 'Codable?' (aka 'Optional<Decodable & Encodable>') be equivalent
yet, as far as I can see MyStruct? (aka Optional) and Codable? (aka Optional<Decodable & Encodable>) are equivalent?
How can I get rid of this error message? Am I doing something that is not meant to be done?
As far as I can see MyStruct? (aka Optional) and Codable? (aka
Optional<Decodable & Encodable>) are equivalent?
No, they are not. MyStruct conforms to Codable but is not equivalent of it.
As in: every MyStruct is Codable but not every Codable is MyStruct.
You can try changing MyType == Codable? to MyType: Codable:
protocol MyProtocolCodable where Self: MyProtocol, MyType: Codable {}
as MyStruct is not equal to Codable?.

var defined in protocol doesn't conform to multiple protocol

I'm struggling with protocols in Swift.
I have defined a protocol like this:
protocol AProtocol {
var property : BProtocol {get set}
}
And I would like to conform to AProtocol in a class with a property that also conform to another protocol. I've tried in these two ways:
class AClass: AProtocol {
var property = BClass()
}
and:
class AClass: AProtocol {
var property: BProtocol & MyBClassType = BProtocol()
}
but none of them seems to work (BClass itself confirm to BProtocol)
This issue is a bit difficult to explain, I hope it was clear.
Is it a limitation of the Swift language?
Do you know a work around to this?
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.

var in protocol as specific protocol

How to describe a variable in a protocol on swift
any type, but supports a specific protocol
Something like this
protocol MyProtocol: class {
var itemsList: AnyObject where Collection { get } // AnyObject supports a Collection protocol
}
Maybe you want:
protocol MyProtocol: class {
associatedtype T: Collection
var itemsList: T { get }
}
If you want T to definitely be an object as well (not a struct) then you must wait for this proposal to make it into the language.
If you want a class to satisfy this protocol with T unspecified in the class's definition, make the class generic.
class C<T: Collection>: MyProtocol {
let itemsList: T
init(_ itemsList: T) {
self.itemsList = itemsList
}
}
let x = C([1,2,3])

How do you structure generic type protocol conformance in Swift?

The following contrived Swift 2 example from real-world code won't compile:
protocol SomeModelType { }
protocol SomeProtocol {
var someVar: SomeModelType? { get }
}
class ConcreteClass<T: SomeModelType>: SomeProtocol {
var someVar: T?
}
This doesn't make sense to me fully. I would assume in ConcreteClass that because I have T being constrained to SomeModelType and have T as the backing type for the someVar property, the compiler would be able to figure out that the SomeProtocol was being conformed to by ConcreteClass.
How should an example like this be structured? Is it possible to the Swift compiler to determine protocol conformance through generic type constraints?
protocol SomeModelType { }
protocol SomeProtocol {
associatedtype T: Any
var someVar: T? { get }
}
class ConcreteClass<T> :SomeProtocol where T: SomeModelType {
var someVar: T?
}

Generic variables in protocols with associated types. Bug? [duplicate]

This question already has answers here:
Unable to use protocol as associatedtype in another protocol in Swift
(2 answers)
Closed 6 years ago.
I'm using Xcode 7.3 and Swift 2.3. I have difficulties using protocols with associated types that have variables. Look at the example:
protocol SomeProtocol {}
class SomeProtocolImpl: SomeProtocol {}
protocol ProtocolWithAssociatedType {
associatedtype T: SomeProtocol
var variable: T { get }
}
class TestClass: ProtocolWithAssociatedType {
var variable: SomeProtocol = SomeProtocolImpl()
}
For some reason, compiler shows errors:
How is that possible? Am I doing something wrong? Is it a bug? A known one?
What I've tried:
defined typealias for that associated type:
class TestClass: ProtocolWithAssociatedType {
typealias O = SomeProtocol
var variable: SomeProtocol = SomeProtocolImpl()
}
nope.
Used method instead:
protocol SomeProtocol {}
class SomeProtocolImpl: SomeProtocol {}
protocol ProtocolWithAssociatedType {
associatedtype T: SomeProtocol
func someMethod() -> T
}
class TestClass: ProtocolWithAssociatedType {
typealias T = SomeProtocol
func someMethod() -> SomeProtocol {
return SomeProtocolImpl()
}
}
just got different errors:
How should I create protocol with associated type and variable and avoid this errors?
The compiler needs a specific type for T that conforms to SomeProtocol.
While this line looks correct
var variable: SomeProtocol
the problem the compiler is running into is that SomeProtocol is not a type, it's a protocol.
The easiest solution, tell the compiler a type to use
var variable: SomeProtocolImpl = SomeProtocolImpl()
or just let it figure it out itself.
var variable = SomeProtocolImpl()