How to correct implement provider logic using generics in Swift - swift

I try to implement logic where some different objects can receive their unique configs.
I have a lot of objects with different types, which can request their own configuration object.
//Provider
protocol ConfigProvider {
func config<R: ConfigReciever>(for reciever: R) -> R.ConfigType
}
class Factory {
}
extension Factory: ConfigProvider {
func config<R: ConfigReciever>(for reciever: R) -> R.ConfigType {
//How switch?
return Config1(info: "hey") as! R.ConfigType
}
}
//Reciever
protocol ConfigReciever: class {
associatedtype ConfigType
var dataSource: ConfigProvider? { get set }
}
struct Config1 {
let info: String
}
class Object1: ConfigReciever {
typealias ConfigType = Config1
var dataSource: ConfigProvider?
func execute() {
let config = dataSource?.config(for: self)
print("\(config!.info)")
}
}
But have some problems with correct implement Provider logic.
I don't know how switch reciever to create correct Config type.
Is this any options?
I know, that i can make this without generics (for example with enum of configTypes), but i don't want to make unnecessary casts.

I would suggest using an intermediate protocol
// Wrapper container
protocol Container { }
extension String: Container { }
extension Int: Container { }
// Implementation
//Provider
protocol ConfigProvider {
func config<R>(for reciever: R) -> Configuration where R : ConfigReciever, R.ConfigType: Configuration
}
class Factory { }
extension Factory: ConfigProvider {
func config<R>(for reciever: R) -> Configuration where R : ConfigReciever, R.ConfigType: Configuration {
return Config1(info: "hey")
}
}
//Reciever
protocol ConfigReciever: class {
associatedtype ConfigType
var dataSource: ConfigProvider? { get set }
}
protocol Configuration {
var info: Container { get set }
}
struct Config1: Configuration {
var info: String
}
class Object1: ConfigReciever {
typealias ConfigType = Config1
var dataSource: ConfigProvider?
func execute() {
let config = dataSource?.config(for: self)
// here you should case into wanted structure:
if let stringInfo = config?.info as? String {
print("\(stringInfo)")
}
}
}
let factory = Factory()
let obj = Object1()
obj.dataSource = factory
obj.execute()

Related

Protocol Conformance Check

How can I perform conformance check against protocol with AssociatedType. Xcode shows error:
Protocol 'MyListener' can only be used as a generic constraint because
it has Self or associated type requirements
My ultimate goal is to extract "MyListener.section" from an array of weakObjects, where the handler matches the function argument.
Note. The NSPointerArray of weakObjects is suppose to capture different types of MyListeners.
public class MyHandler<O,E> {
var source = [O]()
var dest = [E]()
}
public protocol MyListener:class {
var section: Int {get}
associatedtype O
associatedtype E
var handler: MyHandler<O,E>? { get }
}
public class MyAnnouncer {
private let mapWeakObjects: NSPointerArray = NSPointerArray.weakObjects()
public func add<L: MyListener>(listener: L) {
let pointer = Unmanaged.passUnretained(listener).toOpaque()
mapWeakObjects.addPointer(pointer)
}
public func search<O, E> (h:MyHandler<O,E>) -> [Int] {
_ = mapWeakObjects.allObjects.filter { listener in
if listener is MyListener { // Compilation failed
}
if let _ = listener as? MyListener { //Compilation error
}
if listener is MyListener.Type { //Compilation failed
}
}
return [] // ultimate goal is to extract corresponding [MyListener.section].
}
}
Unfortunately, Swift doesn't support protocols with AssociatedType to conformance.
You should try to use Type Erasure. One of the way is to implement type erasure by creating new AnyType class.
Here is another way to release type erasure (example from the internet)
protocol SpecialValue { /* some code*/ }
protocol TypeErasedSpecialController {
var typeErasedCurrentValue: SpecialValue? { get }
}
protocol SpecialController : TypeErasedSpecialController {
associatedtype SpecialValueType : SpecialValue
var currentValue: SpecialValueType? { get }
}
extension SpecialController {
var typeErasedCurrentValue: SpecialValue? { return currentValue }
}
extension String : SpecialValue {}
struct S : SpecialController {
var currentValue: String?
}
var x: Any = S(currentValue: "Hello World!")
if let sc = x as? TypeErasedSpecialController { // Now we can perform conformance
print(sc.typeErasedCurrentValue)
}

Swift: Abstract base class/protocol with private members

I've created an abstract base class-like structure in Swift, using protocol extensions, as per this answer. This is a simplified example:
protocol AbstractBase {
var _constant: Int { get }
func _operation(_ val: Int) -> Int
}
public class ConcreteSub: AbstractBase {
let _constant: Int = 42
func _operation(_ val: Int) -> Int {
return val + 2
}
}
extension AbstractBase {
func mainOperation(_ val: Int) -> Int {
return _operation(val + _constant)
}
}
So basically, ConcreteSub provides the implementation details needed by AbstractBase, namely _constant and _operation.
I would like to hide those details from clients, and only expose mainOperation. However, Swift does not allow me to make the members fileprivate on the protocol -- if I do the following
protocol AbstractBase {
fileprivate var _constant: Int { get }
// etc
I get "error: 'fileprivate' modifier cannot be used in protocols".
Nor can I apply the modifier on the subclass -- when I try
public class ConcreteSub: AbstractBase {
fileprivate let _constant: Int = 42
// etc
I get "error: property '_constant' must be declared internal because it matches a requirement in internal protocol 'AbstractBase'".
Lastly, when I make the whole protocol fileprivate, I get no compile errors, but I consistently run into Linking errors, which I guess is because the protocol is private, but the subclass is public.
Is there another way I'm missing?
When I need an abstract base with some properties/functions hidden I use class with some additional fatalErrors and asserts to crash whenever someone is trying to use Base instead of implementation.
public class AbstractBase {
init() {
assert(type(of: self) != AbstractBase.self, "Abstract class")
}
fileprivate var _constant: Int {
fatalError("Abstract class")
}
fileprivate func _operation(_ val: Int) -> Int {
fatalError("Abstract class")
}
func mainOperation(_ val: Int) -> Int {
return _operation(val + _constant)
}
}
public class ConcreteSub: AbstractBase {
fileprivate override var _constant: Int {
return 42
}
fileprivate override func _operation(_ val: Int) -> Int {
return val + 2
}
}
I actually just ran into this issue. As of Swift 5.1, you can do this instead:
protocol MyProtocol {
var someVisibleVar: String { get }
func someVisibleFunc()
}
fileprivate extension MyProtocol {
var someFilePrivateVar: String {
"whatever"
}
func someFilePrivateFunc() {
print("someFilePrivateFunc() was called with \(someVisibleVar)")
}
}
class SomeClass: MyProtocol {
var someVisibleVar: String { "whatever" }
func someVisibleFunc() {
if someFilePrivateVar == someVisibleVar {
someFilePrivateFunc()
}
}
}
class SomeOtherClass: MyProtocol {
var someVisibleVar: String { "something else" }
func someVisibleFunc() {
if someFilePrivateVar == someVisibleVar {
someFilePrivateFunc()
}
}
}

Does injecting factory make sense in this scenario (Swinject)

What is the right (cleanest and most concise) way to have PetOwner that can at any later point in program create new instances of Cat?
Let's assume that createAnotherAnimal can be called by PetOwner itself after it gets response to some async request, therefore creating as many instances of Cat as needed at the time of creating PetOwner is not possible.
I solved the problem with injecting factory, but I am not convinced that it is the best way to tackle the problem, what are the alternatives in Swinject?
protocol AnimalType {
var name: String? { get set }
func sound() -> String
}
class Cat: AnimalType {
var name: String?
init(name: String?) {
self.name = name
}
func sound() -> String {
return "Meow!"
}
}
protocol PersonType {
func play() -> String
func createAnotherAnimal() -> Void
}
class PetOwner: PersonType {
var pets: [AnimalType] = []
let petFactory : AnimalFactory
init(petFactory : AnimalFactory) {
self.petFactory = petFactory
}
func createAnotherAnimal() {
let pet = petFactory.factoryMethod()
self.pets.append(pet)
}
func play() -> String {
if(pets.count>0) {
let pet : AnimalType = pets[0];
let name = pet.name ?? "someone"
return "I'm playing with \(name). \(pet.sound())"
} else {
return "No animals"
}
}
}
class AnimalFactory {
let factoryMethod : () -> AnimalType
init(factoryMethod: () -> AnimalType) {
self.factoryMethod = factoryMethod
}
}
// Create a container and register service and component pairs.
let container = Container()
container.register(AnimalType.self) { _ in Cat(name: "Mimi") }
container.register(PersonType.self) { r in PetOwner(petFactory: r.resolve(AnimalFactory.self)!) }
container.register(AnimalFactory.self){r in AnimalFactory(factoryMethod:{ () -> AnimalType in r.resolve(AnimalType.self)!}) }
// The person is resolved to a PetOwner with a Cat.
let person = container.resolve(PersonType.self)!
person.createAnotherAnimal()
print(person.play())

How do you work with multiple type parameters - Swift 2?

I am trying to write a generic mediator base class (Mediator) that registers peer classes to specific protocols (on peer class extensions), that are defined on instantiation.
Mediator and Peer subclasses are not supposed to know about each other. Their relationship is defined when all is wired up. This is to make each component modular.
If I use only ONE type parameter such as:
class Mediator<T, U> {
private var peers = [T]()
func registerPeer(peer: T) {
self.peers.append(peer)
}
}
Then one Peer registers correctly.
I want both T or U able to be appended to the peers[].
I am looking for a solution that only modifies Mediator's peers[] and registerPeer() to allow a mix or T or U.
// Mediator
class Mediator<T, U> {
// I want this to be an Array that can be T OR U
private var peers = Array<T|U>()
// I want peer: to be either T OR U
func registerPeer(peer: <T|U>) {
self.peers.append(peer)
}
}
class RootModuleMediator<T, U> : Mediator<T, U> {}
protocol RootModuleMediatorsIOInterface { func someFunction() }
extension RootModuleMediator : RootModuleMediatorsIOInterface { func someFunction() { print("RootModuleMediator someFunction() printed")}}
protocol RootModuleMediatorsViewInterface { func aFunction() }
extension RootModuleMediator : RootModuleMediatorsViewInterface { func aFunction() { print("RootModuleMediator aFunction() printed")}}
// Peer
class Peer<T> {
private var mediator : T?
func registerMediator(mediator: T) { self.mediator = mediator }
}
// View Peer
class RootModuleView<T> : Peer<T> {}
protocol RootModuleViewsMediatorInterface { func someFunction() }
extension RootModuleView : RootModuleViewsMediatorInterface { func someFunction() { print("RootModuleView someFunction() printed") }}
// IO Peer
class RootModuleIO<T> : Peer<T> {}
protocol RootModuleIOsMediatorInterface { func someFunction() }
extension RootModuleIO : RootModuleIOsMediatorInterface { func someFunction() { print("RootModuleIO someFunction() printed") }}
// Wiring components together
let rootModuleIO = RootModuleIO<RootModuleMediatorsIOInterface>()
let rootModuleView = RootModuleView<RootModuleMediatorsViewInterface>()
let rootModuleMediator = RootModuleMediator<RootModuleIOsMediatorInterface, RootModuleViewsMediatorInterface>()
rootModuleIO.registerMediator(rootModuleMediator)
rootModuleView.registerMediator(rootModuleMediator)
rootModuleMediator.registerPeer(rootModuleIO)
rootModuleMediator.registerPeer(rootModuleView)
// I want the following function to print "RootModuleIO someFunction() printed"
rootModuleMediator.peers[0].someFunction()
I do not see the rest of implementation to verify it will all work as expected, but did you mean something like this:
class Mediator<T, U> {
private var peers = [(T, U)]()
func registerPeer(peer: (T, U)) {
self.peers.append(peer)
}
func registerPeer(left: T, _ right: U) {
registerPeer((left, right))
}
}
The missing step was to use tuples as the array elements.
It is possible to have generic types that conform to multiple protocols. It is done like this:
class Mediator<T where T: RootModuleMediatorsIOInterface, T: RootModuleIOsMediatorInterface> {
private var peers = Array<T>()
func registerPeer(peer: T) {
self.peers.append(peer)
}
func exercisePeers() {
for peer in peers {
peer.someFunction()
peer.someOtherFunction()
}
}
}
class RootModuleMediator : RootModuleMediatorsIOInterface, RootModuleIOsMediatorInterface {}
// ############ EXAMPLE PROTOCOL CONSTRAINED EXTENSIONS IMPLEMENTATION ############
protocol RootModuleMediatorsIOInterface { func someFunction() }
extension RootModuleMediatorsIOInterface { func someFunction() { print("Something")}}
protocol RootModuleIOsMediatorInterface { func someOtherFunction() }
extension RootModuleIOsMediatorInterface { func someOtherFunction() { print("Something else") }}
let root = RootModuleMediator()
let mediator = Mediator<RootModuleMediator>()
mediator.registerPeer(root)
mediator.exercisePeers()
I added an exercise function so you can see that you can call the functions implemented by the protocol extensions. I also simplified your protocol and extension definitions. The output is as you would expect:
Something
Something else
In the end, I could not get T or U type parameters to work with the array or function. Having instead opted for a solution that is more suited to my use case of loosely coupling components and making them communicate over defined interfaces.
// Mediator base
class Mediator<IOTypeParam, ViewTypeParam> {
private var IO : IOTypeParam?
private var view : ViewTypeParam?
func registerIOPeer(peer: IOTypeParam) { self.IO = peer }
func registerViewPeer(peer: ViewTypeParam) { self.view = peer }
}
// Mediator subclass
class RootModuleMediator<IOTypeParam, ViewTypeParam> : Mediator<IOTypeParam, ViewTypeParam> {}
protocol RootModuleMediatorsIOInterface { func someFunction() }
extension RootModuleMediator : RootModuleMediatorsIOInterface { func someFunction() { print("RootModuleMediator someFunction() printed")}}
protocol RootModuleMediatorsViewInterface { func aFunction() }
extension RootModuleMediator : RootModuleMediatorsViewInterface { func aFunction() { print("RootModuleMediator aFunction() printed")}}
// Peer base
class Peer<MediatorTypeParam> {
private var mediator : MediatorTypeParam?
func registerMediator(mediator: MediatorTypeParam) { self.mediator = mediator }
}
// View Peer
class RootModuleView<MediatorTypeParam> : Peer<MediatorTypeParam> {}
protocol RootModuleViewsMediatorInterface { func someFunction() }
extension RootModuleView : RootModuleViewsMediatorInterface { func someFunction() { print("RootModuleView someFunction() printed") }}
// IO Peer
class RootModuleIO<MediatorTypeParam> : Peer<MediatorTypeParam> {}
protocol RootModuleIOsMediatorInterface { func someFunction() }
extension RootModuleIO : RootModuleIOsMediatorInterface { func someFunction() { print("RootModuleIO someFunction() printed") }}
// Instances
let rootModuleIO = RootModuleIO<RootModuleMediatorsIOInterface>()
let rootModuleView = RootModuleView<RootModuleMediatorsViewInterface>()
let rootModuleMediator = RootModuleMediator<RootModuleIOsMediatorInterface, RootModuleViewsMediatorInterface>()
// Interface registration
rootModuleIO.registerMediator(rootModuleMediator)
rootModuleView.registerMediator(rootModuleMediator)
rootModuleMediator.registerIOPeer(rootModuleIO)
rootModuleMediator.registerViewPeer(rootModuleView)
// Communication constrained to defined interfaces
rootModuleMediator.IO!.someFunction()
rootModuleMediator.view!.someFunction()
rootModuleIO.mediator!.someFunction()
rootModuleView.mediator!.aFunction()

Implementing Swift protocol with a constrained type parameter

I have a couple of Swift protocols that describe a general interface that I'm trying to implement in multiple ways:
protocol Identifiable
{
var identifier:String { get }
}
protocol ItemWithReference
{
var resolveReference<T:Identifiable>(callback:(T) -> ())
}
Now I want to implement the ItemWithReference protocol using CloudKit as the back end (this will eventually work with an alternate back-end as well, at which time I expect to provide an alternative implementation of the ItemWithReference protocol.
In my CloudKit implementation, I have something like this:
class CloudKitIdentifiable : Identifiable
{
...
}
class CloudKitItemWithReference : ItemWithReference
{
func resolveReference<T:Identifiable>(callback:(T) -> ())
{
// In this implementation, I want to only proceed if `T` is a CloudKitIdentifiable subtype
// But not sure how to enforce that
}
}
What I would like to do is to constrain T to be a CloudKitIdentifiable rather than just a simple Identifiable. I can't do that directly in the resolveReference declaration because then the function wouldn't conform to the ItemWithReference protocol. So instead, I am hoping to confirm that T is indeed a CloudKitIdentifiable and then invoke it's initializer to create a new instance of the class being resolved.
Is there any way in Swift to use T's metatype T.Type and determine if it is a subtype of another type? Furthermore, is there any way to invoke a required initializer that has been declared on that subtype?
try:
class CloudKitIdentifiable : Identifiable {
var identifier:String = ...
required init() {}
// you need `required`.
}
class CloudKitItemWithReference : ItemWithReference {
func resolveReference<T:Identifiable>(callback:(T) -> ()) {
if T.self is CloudKitIdentifiable.Type {
// do work..
let obj = (T.self as CloudKitIdentifiable.Type)()
callback(obj as T)
}
}
}
OR:
class CloudKitItemWithReference : ItemWithReference {
func resolveReference<T:Identifiable>(callback:(T) -> ()) {
if let CKT = T.self as? CloudKitIdentifiable.Type {
// do work..
let obj = CKT()
callback(obj as T)
}
}
}
But, In this case, you have to call resolveReference like this:
let ref = CloudKitItemWithReference()
ref.resolveReference { (obj: CloudKitIdentifiable) -> () in
// ^^^^^^^^^^^^^^^^^^^^ explicit type is necessary.
println(obj.identifier)
return
}
Rathar than that, I would recommend to use Associated Type:
protocol Identifiable {
var identifier:String { get }
}
protocol ItemWithReference {
typealias Item: Identifiable // <-- HERE is associated type
func resolveReference(callback:(Item) -> ())
}
class CloudKitIdentifiable : Identifiable {
var identifier:String
init(identifier: String) {
self.identifier = identifier
}
}
class CloudKitItemWithReference : ItemWithReference {
// `Item` associated type can be inferred from
// the parameter type of `resolveReference()`
//
// typealias Item = CloudKitIdentifiable
func resolveReference(callback:(CloudKitIdentifiable) -> ()) {
let obj = CloudKitIdentifiable(identifier: "test")
callback(obj)
}
}
let ref = CloudKitItemWithReference()
ref.resolveReference { obj in
println(obj.identifier)
return
}