Circular dependency within generic Swift classes - swift

I have generic Parent and Child classes that should both be able to reference each other:
class Parent<MyChild: Child<Parent<MyChild>>> {
var children = [MyChild]()
}
class Child<MyParent: Parent<Child<MyParent>>> {
var parent: MyParent?
}
I want to be able to create subclasses of Parent and Child that have a reference to each other. The generics should allow each class to use methods of the other custom class as well as those inherited by the base Parent and Child classes, which may refer to the custom generics. EDIT: I need not only to reference methods, but instance variables as well.
This may be comparable to an array (the parent) having a reference to the children and each child having a reference to the array it belongs to. The array would be modelled with a generic Child type, and the child should then be modelled with a generic Parent type.
This code produces the compiler error Generic class 'Parent' references itself. I think this is possible in Java. Is there a way of expressing such a generic relationship in Swift?

You can use protocols to define the relationship between these types and the dependencies between them (with an associated type with generic where clause):
protocol Parent: AnyObject {
associatedtype C: Child where C.P == Self
var children: [C] { get set }
}
protocol Child: AnyObject {
associatedtype P: Parent where P.C == Self
var parent: P? { get }
}
(As an aside, I made these AnyObject because this doubly-linked pattern requires that you are dealing with reference types. Also, I made parent property optional because it will need to be weak to avoid strong reference cycles.)
Then the actual parent and child classes can use these protocols:
class Teacher: Parent {
var name: String
var socialSecurityNumber: String
var children: [Student] = []
}
class Student: Child {
var name: String
var admissionDate: Date
weak var parent: Teacher?
...
}
Again, note that parent is a weak property to avoid strong reference cycle.
Note, when using protocols, rather than having abstract (i.e., pure virtual) Child and Parent classes, we have protocol, and our concrete classes would conform to those protocol. And if we wanted to define methods that all of these conforming classes would share, we would define default implementations in a protocol extension. See WWDC 2015 video on Protocol Oriented Programming.

Related

Protocol inheritance with associated type

I have a base protocol that describes the router behavior:
protocol BaseRouterProtocol: AnyObject {
associatedtype View: MainView
func dismiss(viewController: ViewController<View>?)
}
extension BaseRouterProtocol {
func dismiss(viewController: ViewController<View>?) {
viewController?.navigationController?.popViewController(animated: true)
}
}
I want to adopt this protocol to another like this:
protocol StartRouterProtocol: BaseRouterProtocol where View == StartView {
func showTermsVC()
func showSignInVC()
}
But when I create a variable of this type:
let router: StartRouterProtocol
Compiler throws me an error:
Protocol 'StartRouterProtocol' can only be used as a generic constraint because it has Self or associated type requirements
Why does this happening if I have described the type that I expect?
Once a protocol has an associated type, that protocol can't be used as a type by itself for instance declarations-- only for generic constraints and declaring conformance.
So in this case, Swift is saying "yeah, but what is the concrete type for StartRouterProtocol's associated type?"
In this case, it's asking you to either:
Use a concrete type directly, i.e. let router: MyStartViewClass with this conformance declaration, elsewhere: class MyStartViewClass: StartRouterProtocol { ... })
OR, push the need for a concrete type up one layer, as a generic constraint i.e.
class MyRouterController<T: StartRouterProtocol> {
let router: T
}
This is probably not what you were hoping for, but unfortunately associated types add complexity to how you use protocols, especially if you're familiar with generics & interfaces from other languages. (i.e. Java/C# interfaces)
You can work around some aspects of associated types by using a concept called "type erasure" -- but that can cause other problems and complexity.
Here's some further reading that may help: https://medium.com/monstar-lab-bangladesh-engineering/swift-from-protocol-to-associatedtype-then-type-erasure-a4093f6a2d08

Swift: Init() Pattern for Parent/Child Relationship

Setup
Suppose I have two classes:
final class Parent: NSObject
{
var child: Child
}
final class Child: NSObject
{
weak var parent: Parent?
init(parent: Parent)
{
self.parent = parent
}
}
Question:
Now suppose that I want to instantiate a child and establish this relationship in the init() method of Parent. I would do this:
final class Parent: NSObject
{
var child: Child
init()
{
child = Child.init(parent: self) // ERROR!
}
}
Swift whines that I'm using self before super.init(). If I place super.init() before I instantiate child, Swift whines that child isn't assigned a value at the super.init() call.
I've been shutting Swift up by using implicitly-unwrapped optionals, like this:
final class Parent: NSObject
{
var child: Child!
init()
{
super.init()
child.init(parent: self)
}
}
My question is: What do people do in this situation? This is/was a VERY common pattern in Objective-C and Swift produces nothing but headaches. I understand that I could de-couple the assignment of parent from Child's init() so that I could init() child, call super.init(), and then assign parent, but that is not an option in the real-world cases where I run into this. It's also ugly and bloated.
I do realize Swift's intent is to prevent use of an object before it is fully initialized. And that it's possible for child's init() to call back to parent and access state that isn't set up yet, which becomes a danger with the implicitly-unwrapped optional approach.
I cannot find any guidance about Swift best practice here, so I'm asking how people resolve this chicken-and-egg issue. Is turning properties into implicitly unwrapped optionals really the best way around this limitation? Thanks.
You can make it lazy and all your headaches will gone!
final class Parent {
lazy var child = Child(parent: self)
}
final class Child {
weak var parent: Parent?
init(parent: Parent) {
self.parent = parent
}
}
In Swift, all stored properties should be initialized before self is available. Including stored properties in the superclass. So Xcode doesn't let you use self till then. But using lazy means that it is initialized before. So you can use self freely.
Some helpful notes:
Don't inherit from NSObject if you don't need objc advanced features for your class.
In swift naming convention, open parentheses ( will read as with in objective-C. So you don't need withParent as a label in your initializer.
Use internal and external naming of arguments as the convention suggests.
Also note that some of the above notes are written before comments

Swift Generics - Attempting to make a generic protocol concrete fails when attempting to use specialised sub-protocol as variable

I want to know why my SomeResourceRepository is still generic, even though it is only defined in one case only, which is when I set ResourceType = SomeResource, which XCode formats as below with the where clause. Code below which shows the exact setup I'm trying to achieve, written in a Playground.
I am trying to define a generic protocol for any given ResourceType such that the ResourceTypeRepository protocol then automatically requires the same set of functions, without having to copy-paste most of GenericRepository only to manually fill in the ResourceType for each Repository I make. The reason I need this as a protocol is because I want to be able to mock this for testing purposes later. So I'll provide an implementation of said protocol somewhere else in the actual app.
My interpretation of the code below is that it should work, because both SomeResourceLocalRepository and SomeResourceRemoteRepository are concrete, as I have eliminated the associated type by defining them "on top of" SomeResourceRepository, which is only defined where ResourceType == SomeResource.
import Foundation
struct SomeResource: Identifiable {
let id: String
let name: String
}
struct WhateverResource: Identifiable {
let id: UUID
let count: UInt
}
protocol GenericRepository: class where ResourceType: Identifiable {
associatedtype ResourceType
func index() -> Array<ResourceType>
func show(id: ResourceType.ID) -> ResourceType?
func update(resource: ResourceType)
func delete(id: ResourceType.ID)
}
protocol SomeResourceRepository: GenericRepository where ResourceType == SomeResource {}
protocol SomeResourceLocalRepository: SomeResourceRepository {}
protocol SomeResourceRemoteRepository: SomeResourceRepository {}
class SomeResourceLocalRepositoryImplementation: SomeResourceLocalRepository {
func index() -> Array<SomeResource> {
return []
}
func show(id: String) -> SomeResource? {
return nil
}
func update(resource: SomeResource) {
}
func delete(id: String) {
}
}
class SomeResourceService {
let local: SomeResourceLocalRepository
init(local: SomeResourceLocalRepository) {
self.local = local
}
}
// Some Dip code somewhere
// container.register(.singleton) { SomeResourceLocalRepositoryImplementation() as SomeResourceLocalRepository }
Errors:
error: Generic Protocols.xcplaygroundpage:45:16: error: protocol 'SomeResourceLocalRepository' can only be used as a generic constraint because it has Self or associated type requirements
let local: SomeResourceLocalRepository
^
error: Generic Protocols.xcplaygroundpage:47:17: error: protocol 'SomeResourceLocalRepository' can only be used as a generic constraint because it has Self or associated type requirements
init(local: SomeResourceLocalRepository) {
I will probably have to find another way to accomplish this, but it is tedious and quite annoying as we will produce a lot of duplicate code, and when we decide to change the API of our repositories, we will have to manually change it for all the protocols as we don't follow a generic "parent" protocol in this work-around.
I have read How to pass protocol with associated type as parameter in Swift and the related question found in an answer to this question, as well as Specializing Generic Protocol and others.
I feel like this should work, but it does not. The end goal is a concrete protocol that can be used for dependency injection, e.g. container.register(.singleton) { ProtocolImplementation() as Protocol } as per Dip - A simple Dependency Injection Container, BUT without copy-pasting when the protocol's interface clearly can be made generic, like in the above.
As swift provides a way to declare generic protocols (using associatedtype keyword) it's impossible to declare a generic protocol property without another generic constraint. So the easiest way would be to declare resource service class generic - class SomeResourceService<Repository: GenericRepository>.
But this solution has a big downside - you need to constraint generics everywhere this service would be involved.
You can drop generic constraint from the service declaration by declaring local as a concrete generic type. But how to transit from generic protocol to the concrete generic class?
There's a way. You can define a wrapper generic class which conforms to GenericRepository. It does not really implements its methods but rather passes to an object (which is real GenericRepository) it wraps.
class AnyGenericRepository<ResourceType: Identifiable>: GenericRepository {
// any usage of GenericRepository must be a generic argument
init<Base: GenericRepository>(_ base: Base) where Base.ResourceType == ResourceType {
// we cannot store Base as a class property without putting it in generics list
// but we can store closures instead
indexGetter = { base.index() }
// and same for other methods or properties
// if GenericRepository contained a generic method it would be impossible to make
}
private let indexGetter: () -> [ResourceType] {
indexGetter()
}
// ... other GenericRepository methods
}
So now we have a concrete type which wraps real GenericRepository. You can adopt it in SomeResourceService without any alarm.
class SomeResourceService {
let local: AnyGenericRepository<SomeResource>
}

Array of slightly different generics

I have a class that takes a generic type, which must inherit from class WorldObject:
class WorldObjectsProvider<WorldObjectType: WorldObject>
This class will be creating objects of class WorldObjectType and return them in one function. Now I would like to create an array of such classes (WorldObjectsProvider), but I want this array to be able to keep many different types of generic classes WorldObjectsProvider, for example:
class TestObject: WorldObject { }
let providers: [WorldObjectsProvider<WorldObject>] = [WorldObjectsProvider<WorldObject>(), WorldObjectsProvider<TestObject>()]
In general I think this might be possible, as all generic types are supposed to inherit from WorldObject. This could work by returning all values as references to base class WorldObject. But I guess this might be too much for generics. Is there some way to create such an array?
Swift generic types are invariant in respect to their generic arguments, which means that MyGeneric<A> is incompatible with MyGeneric<B>, even if A: B.
This being said, if you need to use two different generics, you need a common denominator for the two generics. A type eraser is one of the possible solutions:
struct AnyProvider<T: WorldObject> {
init<U: WorldObject>(_ provider: WorldObjectsProvider<U>) { }
}
let providers: [AnyProvider<WorldObject>] = [AnyProvider(WorldObjectsProvider<WorldObject>()), AnyProvider(WorldObjectsProvider<TestObject>())]
This will allow you to use multiple types of generics in the same collections, provided they have a common ground. The downside is the fact that the type eraser will likely have to mimic and forward all public methods of the original type.
For example, if the original provider has a func someProviderMethod() method, then AnyProvider will also have to declare it:
struct AnyProvider<T: WorldObject> {
private let _someProviderMethod: () -> Void
init<U: WorldObject>(_ provider: WorldObjectsProvider<U>) {
_someProviderMethod = provider.someProviderMethod
}
func someProviderMethod() {
_someProviderMethod()
}
}

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

In Objective-C, it's possible to write something like that:
#property(retain) UIView<Protocol1, Protocol2, ...> *myView;
But how can I write this code in swift?
I already know how to make a property conform to many protocols, but it does not work by using the inheritance:
var myView: ??? protocol<Protocol1, Protocol2, ...>
Edit:
I use many UIView subtypes like UIImageView, UILabel or others, and I need to use some of the UIView properties plus some methods defined in the protocols. In the worst case I could create a UIViewProtocol with the needed properties, but I would know if it is possible in Swift to declare a property/variable with a type and some protocol to conform with.
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
// ...
}
In Swift 4 it's finally possible. You can declare variable of some class conforming to protocol at the same time, like this:
class ClassA {
var someVar: String?
}
protocol ProtocolA {}
class ClassB {
var someOptional: (ClassA & ProtocolA)? // here is optional value
var some: ClassA & ProtocolA // here is non-optional value; need to provide init though :)
}
One and probably a bit ugly one of the ways to do that, is to create a wrapper protocol for UIView:
protocol UIViewRef {
var instance: UIView { get }
}
Now it is possible to create a protocol which implements Protocol1, Protocol2 and UIViewRef, which is going to be used to get the UIView itself:
protocol MyUIViewProtocol: UIViewRef, Protocol1, Protocol2 { }
And last step will be implementing UIViewRef protocols for your UIViews, which, in you case, as I understand, already implement Protocol1 and Protocol2:
// SomeOfMyViews already implements Protocol1 and Protocol2
extension SomeOfMyUIViews: MyUIViewProtocol {
var instance: UIView { return self }
}
As the result we have MyUIViewProtocol, implementers of which hold a reference to a UIView and each of them implement
Protocol1 and Protocol2. One caveat though - to get the UIView itself, we need to ask it's reference from instance
property. For example
// Lets say we're somewhere in a UIViewController
var views: [SomeOfMyUIView] = // Get list of my views
views.forEach { self.view.addSubview($0.instance) }