How to apply Inheritance to Generics in Swift - swift

I have a generic Container struct that is stored as a container of a class that implements a protocol as below:
protocol Protocol {}
class Class : Protocol {}
struct Container<Element> {
var value:Element
init(_ v:Element) { value = v }
}
class Example {
var container : Container<Class>
init() { container = Container(Class()) }
func getContainer() -> Container<Protocol> { return container }
}
However when I pass it I want to pass it as a Container of just the protocol which is generating an error on return container:
Cannot convert return expression of type 'Container<Class>' to return type 'Container<Protocol>'
I know this should be possible as Swift does it with arrays as below:
class ArrayExample {
var arrayContainer : [Class]
init() { arrayContainer = [Class()] }
func getArrayContainer() -> [Protocol] { return arrayContainer }
}
So does anyone have any thoughts on how to implement Container so that the conversion/copy doesn't create the error

It isn't clear what you're actually trying to accomplish, but here's code that compiles and that covers all the goals you've expressed so far:
protocol Protocol {}
class Class : Protocol {
var thing : AnyObject?
}
class Container<Element> {
var value:Element
init(_ v:Element) { value = v }
}
class Example {
var container : Container<Protocol>
init() { container = Container(Class()) }
func getContainer() -> Container<Protocol> { return container }
func doStuff() {
if let v = container.value as? Class { v.thing = "ha" }
}
}

Related

How can I get a specific struct type returned?

I want to initialize the struct by receiving the "struct type"(?) by a specific logic as below.
As I abstracted the return value of the struct into MyProtocol had a declaration of init(), which seems a little awkward.
I'm not sure I can do this.
I'd like to get an undecided struct type returned, what should I do?
Is this for the best?
For your information, Opaque Type is not available because it needs to support iOS 13 or earlier.
protocol MyProtocol {
init() // Is this for the best?
}
struct AAA: MyProtocol {
var numberAAA: Int // Sample variable.
init() {
print("init AAA")
numberAAA = 100
}
}
struct BBB: MyProtocol {
var numberBBB: Int // Sample variable.
init() {
print("init BBB")
numberBBB = 200
}
}
class MyClass {
func mainLogic() {
let myStruct = randomStruct()
myStruct.init() // This is the reason init () declared in the MyProtocol.
}
func randomStruct() -> MyProtocol.Type {
if Bool.random() {
return AAA.self
} else {
return BBB.self
}
}
}
init() as a protocol requirement seems odd. No one is stopping you to do this and compiler should allow this, however I would consider making protocol based on some other requirement rather than just init().
Here's an attempt to do so -
protocol NumberOperation {
var number: Int { get set }
mutating func perform()
}
struct Incrementer: NumberOperation {
var number: Int
mutating func perform() {
number += 1
}
}
struct Decrementer: NumberOperation {
var number: Int
mutating func perform() {
number -= 1
}
}
struct Record<O: NumberOperation> {
public var operation: O
mutating func perform() {
operation.perform()
}
}
class MyClass {
func mainLogic() {
var record = getRecord(type: Incrementer.self)
record.perform()
}
func getRecord<O: NumberOperation>(type: O.Type) -> Record<O> {
if type == Incrementer.self {
return Record(operation: Incrementer(number: 1) as! O)
}
return Record(operation: Decrementer(number: 10) as! O)
}
}
This introduces a container type Record that holds/wraps our type based on the same protocol conformation. This does the same what you were doing, probably is easier to read/understand.

Protocol associatedtype as a type for delegate

The purpose of what I am trying to do is to make it possible to put objects which implements ChildOfRootClass to one array (look at AbstractClass -> children) and put at each ChildNClass instance object a link to its parent (look weak var delegate variable). So I want make type of delegate in each ChildOfRootClass generic.
Hope code will explain what exactly I have meant.
// Parent class for RootClass and Child1Class, Child2Class etc
class AbstractClass {
init() { }
init(smth: String) { }
var children = [String : ChildOfRootClass]()
func add(key: String, child: ChildOfRootClass) {
children[key] = child
}
}
Delegate protocols for each of children.
protocol ChildDelegate: class { }
protocol Child1ClassDelegate: ChildDelegate { func rr() }
protocol Child2ClassDelegate: ChildDelegate { }
class RootClass: AbstractClass {
override init() {
super.init()
}
}
extension RootClass: Child1ClassDelegate {
func rr() { }
}
Children classes.
protocol ChildOfRootClass {
associatedtype ChildOfRootClassDelegateType: ChildDelegate
weak var delegate: ChildOfRootClassDelegateType? { set get }
init(smth: String)
}
class Child1Class: AbstractClass, ChildOfRootClass {
typealias ChildOfRootClassDelegateType = Child1Delegate
weak var delegate: Child1Delegate?
required override init(smth: String) {
super.init(smth: smth)
}
}
extension Child1Class: Child2ClassDelegate { }
class Child2Class: AbstractClass/*, ChildOfRootClass*/ {
required override init(smth: String) {
super.init(smth: smth)
}
}
How I want to use it.
let root = RootClass()
let child1 = Child1Class(smth: "1")
let child2 = Child2Class(smth: "2")
child1.add(key: "child2", child: child2)
root.add(key: "child1", child: child1)

Swift override generic swift

I am trying to implement generic for MVVM Swift. I have two base class, an protocol for generic class. The special in here is inheritance. I tried for three hour but I can't fix it :(.
protocol ObjectProtocol {
var id: Int { get set }
var name: String { get set }
}
class BaseViewModel<T: ObjectProtocol> {
var objects: [T] = []
init(){
}
}
protocol ListViewControllerType {
associatedtype T: ObjectProtocol
associatedtype ViewModelType: BaseViewModel<T>
var viewModel: ViewModelType! { get set }
func showError(error: String)
}
extension ListViewControllerType {
func showError(error: String) {
print(error)
}
}
class Consult: ObjectProtocol {
var id: Int = 1
var name: String = "Consult"
}
class ConsultViewModel<T: Consult>: BaseViewModel<Consult> {
}
class ConsultViewController: ListViewControllerType {
var viewModel: ConsultViewModel<Consult>!
}
But I get error in var viewModel: ConsultViewModel<Consult>!
This is error: Type 'ConsultViewController' does not conform to protocol 'ListViewControllerType'
Someone have experience with generic and inheritance can help me please.
Thank you so much.
I usually do like this:
class BaseViewModel {
}
class TemplateViewModel<T: ObjectProtocol>: BaseViewModel {
var objects: [T] = []
init(){
}
}

Swift protocol requring method returning protocols

I am trying to make following code compile.
Basically I want to have object conforming multiple protocols, for example network service that exposes different groups of API to different parts of app (for example: login API to loginController, sharing API to shareController)
+
I want this service to be injected using networkXProvider protocols e.g. implement Dependency Injection (for example I want to pass to LoginController an Injection that adopts LoginControllerProvider and FetchingUsersFromDBProvider):
protocol MyAccountCommunicator {
func getAccountData() -> String
}
protocol EventsCommunicator {
func getEvents() -> String
}
class NetworkManager: MyAccountCommunicator, EventsCommunicator {
func getAccountData() -> String {
return "Accounts"
}
func getEvents() -> String {
return "Events"
}
}
protocol MyAccountCommunicatorProvider {
var networkCommunicator: MyAccountCommunicator { get }
}
protocol EventsCommunicatorProvider {
var networkCommunicator: EventsCommunicator { get }
}
class Injector: MyAccountCommunicatorProvider, EventsCommunicatorProvider {
var networkCommunicator: NetworkManager = NetworkManager()
}
Playground fails with following error:
error: strings.playground:29:7: error: type 'Injector' does not
conform to protocol 'MyAccountCommunicatorProvider' class Injector:
MyAccountCommunicatorProvider, EventsCommunicatorProvider {
^
strings.playground:30:9: note: candidate has non-matching type
'NetworkManager'
var networkCommunicator: NetworkManager = NetworkManager()
^
error: strings.playground:29:7: error: type 'Injector' does not
conform to protocol 'EventsCommunicatorProvider' class Injector:
MyAccountCommunicatorProvider, EventsCommunicatorProvider {
^
strings.playground:30:9: note: candidate has non-matching type
'NetworkManager'
var networkCommunicator: NetworkManager = NetworkManager()
Environment: swift4, XCode9
Why do you need MyAccountCommunicatorProvider and EventsCommunicatorProvider protocols? What if you combine them into one?
protocol CommunicatorProvider {
var networkCommunicator: NetworkManager { get }
}
class Injector: CommunicatorProvider {
var networkCommunicator = NetworkManager()
}
protocol MyAccountCommunicator {
func getAccountData() -> String
}
protocol EventsCommunicator {
func getEvents() -> String
}
protocol MyAccountCommunicatorProvider {
var accountCommunicator: MyAccountCommunicator { get }
}
protocol EventsCommunicatorProvider {
var eventCommunicator: EventsCommunicator { get }
}
class NetworkManager: MyAccountCommunicator, EventsCommunicator {
func getAccountData() -> String {
return "Accounts"
}
func getEvents() -> String {
return "Events"
}
}
class Injector: MyAccountCommunicatorProvider, EventsCommunicatorProvider {
var networkManager = NetworkManager()
var accountCommunicator: MyAccountCommunicator {
return networkManager
}
var eventCommunicator: EventsCommunicator {
return networkManager
}
}
You can use like this :
protocol MyAccountCommunicatorProvider {
var networkCommunicator1: MyAccountCommunicator { get }
}
protocol EventsCommunicatorProvider {
var networkCommunicator2: EventsCommunicator { get }
}
class Injector: MyAccountCommunicatorProvider, EventsCommunicatorProvider {
var networkCommunicator: NetworkManager = NetworkManager()
lazy var networkCommunicator1: MyAccountCommunicator = {
return networkCommunicator
}()
lazy var networkCommunicator2: EventsCommunicator = {
return networkCommunicator
}()
}

swift 3 downcast to dynamic class

I am trying to create a couple of objects which are dependent one to each other and they mush have a method to downcast directly the concrete class of the other object. Something like this:
protocol aProt
{
var bVar:bProt! { get set }
}
protocol bProt
{
var aVar:aProt! { get set }
}
class a: aProt
{
var bVar: bProt!
func bConcrete() -> b {
return bVar as! b
}
}
class b: bProt
{
var aVar: aProt!
func aConcrete() -> a {
return aVar as! a
}
Now, the problem is that I want this behavior (func aConcrete(),func bConcrete()) to be inherited by the subclasses of a and b. Then I thought the perfect way of doing this was using generics, but... There's no way of doing this.
class a: aProt
{
var bVar: bProt!
func bConcrete() -> T {
return bVar as! T
}
}
class b: bProt
{
var aVar: aProt!
func aConcrete<T>() -> T {
return aVar as! T
}
You can do it but when you have to use it you must downcast the variable anyway, so there is no way of doing it in a clean manner:
let aObject = a()
let bSubclassObject = a.bConcrete() // The compiler complains it cannot infer the class of T
let bSubclassObject = a.bConcrete() as! bSubclass // this works, but this is exactly which I wanted to avoid... :(
Define the generic function and add where to T:
protocol aProt {
var bVar: bProt! { get set }
}
protocol bProt {
var aVar:aProt! { get set }
}
class a: aProt {
var bVar: bProt!
func bConcrete<T: b>(_ type: T.Type) -> T? {
return bVar as? T
}
}
class b: bProt {
var aVar: aProt!
func aConcrete<T: a>(_ type: T.Type) -> T? {
return aVar as? T
}
}
class a1: a { }
class b1: b {
var fullName: String = "new object"
}
let aObj = a()
aObj.bVar = b1()
let bObj = aObj.bConcrete(b1.self)
bObj?.fullName
According to your requirement, calls bConcrete(b1.self) might still not good enough, but at least you need to know what type of data you are expecting to return.