Here is the Protocols:
protocol WireFrameProtocol{
// router for all normal cases
// like showing login page
}
protocol InteractorProtocol{
var wireFrame: WireFrameProtocol? { get set }
}
protocol HomeWireFrameProtocol: WireFrameProtocol{
// home specific routers
}
protocol HomeInteractorProtocol: InteractorProtocol{
var wireFrame: HomeWireFrameProtocol? { get set }
}
class Test: HomeInteractorProtocol{
var wireFrame: HomeWireFrameProtocol?
}
extension Test: InteractorProtocol{
}
WireFrameProtocol will have all the routing functions. HomeWireFrameProtocol will extend and have some home relating routing only. The test class inherits from HomeInteractorProtocol, which has a var wireFrame: HomeWireFrameProtocol, again HomeWireFrameProtocol is extending WireFrameProtocol.
Is var wireFrame: HomeWireFrameProtocol also represent var wireFrame: WireFrameProtocol?
Ok I realise it now, and fixed my own problem. What I did was
protocol HomeInteractorProtocol: InteractorProtocol{
// do not create another variable to store HomeWireFrame
// var wireFrame: HomeWireFrameProtocol? { get set }
}
The variable wireFrame: WireFrameProtocol can also hold the reference of HomeWireFrameProtocol.
so in Test class I updated:
class Test: HomeInteractorProtocol{
// can use all features from the WireFrameProtocol
var wireFrame: WireFrameProtocol?
// also can use all the feature from HomeWireFrame
// this is kind of what I want to achieve without creating two different variables in the protocols
var homeWireFrame: HomeWireFrameProtocol? {
return wireFrame as? HomeWireFrameProtocol
}
}
extension Test: InteractorProtocol{
}
If I understand your question correctly then you have just encountered a traditional Dimond Problem where it is ambiguous as to which parent class a particular feature is inherited from.
Your view and wireFrame both the variable declared in HomeViewPresenterProtocol and HomeViewInteractorOutputProtocol. So when you confirm these two protocols in HomeViewPresenter the Dimond problem arise. Compiler is confusing to this ambiguous parent.
The easiest solution is to change the variable name as you can't have the same variable or function signature.
Related
Note: Sorry could not come-up with better title than this, so please
suggest a better one if you come across one after reading the question
I have a BasePresenter class, That should take BaseInteractor and BaseRouter as its init arguments, and each child class of BasePresenter should be able to specify subclass of BaseInteractor and BaseRouter in their implementation
So I have declared my BasePresenter as
open class PRBasePresenter<T: PRBaseInteractor, R: PRBaseRouter> {
var interactor: T!
var router: R!
let disposeBag = DisposeBag()
convenience init(with router : R, interactor : T) {
self.init()
self.router = router
self.interactor = interactor
}
}
So now PRBaseCollectionsPresenter which is a child of PRBasePresenter declares its interactor and router as
class PRBaseCollectionsPresenter: PRBasePresenter<PRBaseCollectionsInteractor, PRBaseCollectionRouter> {
//other code here
}
Obviously PRBaseCollectionsInteractor is a subclass of PRBaseInteractor and PRBaseCollectionRouter is a subclass of PRBaseRouter
Everything works till here fine. Now comes the issue. Every ViewController should have presenter as a property. So I have a protocol which mandates that with
protocol PresenterInjectorProtocol {
var presenter : PRBasePresenter<PRBaseInteractor, PRBaseRouter>! { get set }
}
And my BaseViewController confirms to PresenterInjectorProtocol
public class PRBaseViewController: UIViewController,PresenterInjectorProtocol {
var presenter: PRBasePresenter<PRBaseInteractor, PRBaseRouter>!
//other code...
}
Now lets say I have ChildViewController, it will obviously get presenter because of inheritance, but obviously child would want to have its specific presenter than having a generic one. And obviously in Swift when you override a property you cant change the type of the variable. So the only way is
class PRBaseTableViewController: PRBaseViewController {
var tableSpecificPresenter: PRBaseCollectionsPresenter {
get {
return self.presenter as! PRBaseCollectionsPresenter
}
}
//other code goes here
}
This gives me a warning
Cast from 'PRBasePresenter!' to
unrelated type 'PRBaseCollectionsPresenter' always fails
And trying to ignore it and running will result in crash :(
How can I solve this problem? What am I doing wrong? Or is this approach completely wrong?
So I have two ViewControllers. First (MapVC) with map and second (SettingsVC) with many settings that need to be applied to this map.
I thought it would be nice idea to create protocol like
protocol MapSettingsDelegate: class {}
I know that I can specify function inside this protocol. But how I should do it when I have many settings - how should I pass them from SettingsVC to MapVC.
Example:
struct MySettings {
var value1: String
var value2: String
// and so on...
}
protocol MapSettingsDelegate: class {
func settingsUpdated(newSettings: MySettings)
}
and implement it inside your controller
class MapVC : MapSettingsDelegate {
...
func settingsUpdated(newSettings: MySettings) {
// Update everything you need
}
...
}
Feel free to ask for details
Consider code like this:
protocol SomeProtocol {
var something: Bool { get set }
}
class SomeProtocolImplementation: SomeProtocol {
var something: Bool = false {
didSet {
print("something changed!")
}
}
}
protocol MyProtocol {
var myProperty: SomeProtocol { get }
}
class MyClass: MyProtocol {
var myProperty: SomeProtocol = SomeProtocolImplementation() {
didSet {
print("myProperty has changed")
}
}
}
var o: MyProtocol = MyClass()
o.myProperty.something = true
This code doesn't compile with error:
error: cannot assign to property: 'myProperty' is a get-only property
o.myProperty.something = true
~~~~~~~~~~~~ ^
Why? My property is of type of SomeProtocolImplementation, which is class type so it should be possible to modify it's inner property using reference to myProperty.
Going further, after modifying myProperty definition so that it looks like that:
var myProperty: SomeProtocol { get set }
something weird happens. Now the code compile (not a surprise), but the output is:
something changed!
myProperty has changed
So at this point SomeProtocolImplementation starts behaving like a value type - modyifing it's internal state causes that the "didSet" callback for myProperty is triggered. Just as SomeProtocolImplementation would be struct...
I actually find the solution, but I want also understand what's going on. The solution is to modify SomeProtocol definition to:
protocol SomeProtocol: class {
var something: Bool { get set }
}
It works fine, but I'm trying to understand why it behaves like this. Anybody able to explain?
First read what Class Only Protocol is. Concentrate on the note section that says:
Use a class-only protocol when the behavior defined by that protocol’s requirements assumes or requires that a conforming type has reference semantics rather than value semantics.
Above quote should get you the idea.
You are trying to get the behavior of reference type for your SomeProtocol's conforming class (i.e. SomeProtocolImplementation). You want to be able to change the value of something in future. So basically you are directing to the above quoted sentence.
If you need more clarification please consider the following more meaningful design where I changed the naming for convenience:
protocol Base: class {
var referenceTypeProperty: Bool { get set }
// By now you are assuming: this property should be modifiable from any reference.
// So, instantly make the protocol `Class-only`
}
class BaseImplementation: Base {
var referenceTypeProperty: Bool = false {
didSet {
print("referenceTypeProperty did set")
}
}
}
protocol Child {
var valueTypeProperty: Base { get }
// This property shouldn't be modifiable from anywhere.
// So, you don't need to declare the protocol as Class-only
}
class ChildImplementation: Child {
var valueTypeProperty: Base = BaseImplementation() {
didSet {
print("valueTypeProperty did set")
}
}
}
let object: Child = ChildImplementation()
object.valueTypeProperty.referenceTypeProperty = true
Any class that can provide behavior useful to other classes may declare a programmatic interface for vending that behavior anonymously. Any other class may choose to adopt the protocol and implement one or more of its methods, thereby making use of the behavior. The class that declares a protocol is expected to call the methods in the protocol if they are implemented by the protocol adopter.
Protocol Apple Documentation
When you try to 'set' value to a variable that is read-only - you are trying to change the protocol's implementation. Conforming classes can only consume information from protocol. In Swift we can write protocol extensions where we can have alternative methods for the protocol.
In short think of computed variables as functions. You are technically trying to change a function in this case.
I actually find the solution, but I want also understand what's going on.
I was just about to tell you to make SomeProtocol a class protocol, but you already figured that out. — So I'm a little confused as to what you don't understand.
You understand about reference types and value types, and you understand about class protocols and nonclass protocols.
Well, as long as SomeProtocol might be adopted by a struct (it's a nonclass protocol), then if you are typing something as a SomeProtocol, it is a value type. The runtime isn't going to switch on reference type behavior just because the adopter turns out to be a class instance; all the decisions must be made at compile time. And at compile time, all the compiler knows is that this thing is a SomeProtocol, whose adopter might be a struct.
Okay so I have this protocol MenuEntry which I want to use to populate a TableView:
protocol MenuEntry {
static var title: String { get }
static func entrySelected(_ menuController: MenuController)
}
I want to implement this protocol in various places and let the item itself decide what to do. It might be a UIViewController which implements the protocol or a simple struct, which then calls a function on the menu itself:
struct SomeEntry: MenuEntry {
static var title: String { return "Some Entry" }
static func entrySelected(_ menuController: MenuController) {
menuController.doSomething()
}
}
Now I want to build the MenuControllers datasource but without actually instantiating the entries because especially my view controllers are not necessarily available when the MenuControllers datasource is populated. Thats why I use static var/func in MenuEntry. Currently, I can simply do this to populate the datasource:
let dataSource: [MenuEntry.Type] = [SomeEntry.self]
And it seems to work pretty well. I can get the entries and call the corresponding functions:
dataSource.first?.title //Gives me "Some Entry"
Now comes the tricky part. I thought I could be really clever and create a protocol extension where I reference all the types in which I implement the protocol like so:
extension MenuEntry {
static var someEntry: MenuEntry.Type { return SomeEntry.self }
//...
}
And then later use them via MenuEntry.someEntry. However, accessing someEntry on MenuEntry gives me an error:
error: static member 'someEntry' cannot be used on protocol metatype 'MenuEntry.Protocol'
So my question is: what am I missing? Am I just trying to misuse the language in a way which is not intended or am I just doing something wrong?
SOLUTION
From the accepted answer below, heres how I now do things. First, we need the mentioned struct (no need for a class I guess):
struct MenuEntries {}
Then, where ever I implement the MenuEntry protocol, I also extend this struct and add the entry like so:
struct SomeEntry: MenuEntry {
static var title: String { return "Some Entry" }
static func entrySelected(_ menuController: MenuController) {
menuController.doSomething()
}
}
extension MenuEntries {
static var someEntry: MenuEntry.Type { return SomeEntry.self }
}
The last thing is to create my datasource like so:
let dataSource: [MenuEntry.Type] = [MenuEntries.someEntry, ...]
Okay, now I have a list of all menu entries in one place. The downside is I have to remember to extend MenuEntries every time. Except there is some magical way to extend a struct on a conditional base I'm not aware of. But I guess thats just over the top and simply not possible.
From The Swift Book
A protocol defines a blueprint of methods, properties, and other requirements that suit a particular task or piece of functionality. The protocol can then be adopted by a class, structure, or enumeration to provide an actual implementation of those requirements.”
Your extension is attempting to implement functionality directly in the protocol, but this is not allowed; Only a class, structure or enumeration adopting the protocol can provide functionality.
You could define a class that returns your menu classes:
class MenuFactory {
static var someEntry: MenuEntry.type { return SomeEntry.self }
}
This is my inheritance structure
Protocols
protocol BaseProtocol {
}
protocol ChildProtocol: BaseProtocol {
}
Classes
class BaseClass: NSObject {
var myVar: BaseProtocol!
}
class ChildClass: BaseClass {
override var myVar: ChildProtocol!
}
I'm receiving a compiler error:
Property 'myVar' with type 'ChildProtocol!' cannot override a property with type 'BaseProtocol!'
What is the best approach to achieve this?
UPDATE
I updated the question trying to implement the solution with generics but it does not work :( This is my code (now the real one, without examples)
Protocols
protocol TPLPileInteractorOutput {
}
protocol TPLAddInteractorOutput: TPLPileInteractorOutput {
func errorReceived(error: String)
}
Classes
class TPLPileInteractor<T: TPLPileInteractorOutput>: NSObject, TPLPileInteractorInput {
var output: T!
}
And my children
class TPLAddInteractor<T: TPLAddInteractorOutput>: TPLPileInteractor<TPLPileInteractorOutput>, TPLAddInteractorInput {
}
Well, inside my TPLAddInteractor I can't access self.output, it throws a compiler error, for example
'TPLPileInteractorOutput' does not have a member named 'errorReceived'
Besides that, when I create the instance of TPLAddInteractor
let addInteractor: TPLAddInteractor<TPLAddInteractorOutput> = TPLAddInteractor()
I receive this other error
Generic parameter 'T' cannot be bound to non-#objc protocol type 'TPLAddInteractorOutput'
Any thoughts?
#tskulbru is correct: it can't be done, and this has nothing to do with your protocols. Consider the example below, which also fails…this time with Cannot override with a stored property 'myVar':
class Foo {
}
class Goo: Foo {
}
class BaseClass: NSObject {
var myVar: Foo!
}
class ChildClass: BaseClass {
override var myVar: Foo!
}
To understand why, let's reexamine the docs:
Overriding Properties
You can override an inherited instance or class property to provide
your own custom getter and setter for that property, or to add
property observers to enable the overriding property to observe when
the underlying property value changes.
The implication is that if you are going to override a property, you must write your own getter/setter, or else you must add property observers. Simply replacing one variable type with another is not allowed.
Now for some rampant speculation: why is this the case? Well, consider on the one hand that Swift is intended to be optimized for speed. Having to do runtime type checks in order to determine whether your var is in fact a Foo or a Bar slows things down. Then consider that the language designers likely have a preference for composition over inheritance. If both of these are true, it's not surprising that you cannot override a property's type.
All that said, if you needed to get an equivalent behavior, #tskulbru's solution looks quite elegant, assuming you can get it to compile. :)
I don't think you can do that with protocols
The way i would solve the problem you are having is with the use of generics. This means that you essentially have the classes like this (Updated to a working example).
Protocols
protocol BaseProtocol {
func didSomething()
}
protocol ChildProtocol: BaseProtocol {
func didSomethingElse()
}
Classes
class BaseClass<T: BaseProtocol> {
var myProtocol: T?
func doCallBack() {
myProtocol?.didSomething()
}
}
class ChildClass<T: ChildProtocol> : BaseClass<T> {
override func doCallBack() {
super.doCallBack()
myProtocol?.didSomethingElse()
}
}
Implementation/Example use
class DoesSomethingClass : ChildProtocol {
func doSomething() {
var s = ChildClass<DoesSomethingClass>()
s.myProtocol = self
s.doCallBack()
}
func didSomething() {
println("doSomething()")
}
func didSomethingElse() {
println("doSomethingElse()")
}
}
let foo = DoesSomethingClass()
foo.doSomething()
Remember, you need a class which actually implements the protocol, and its THAT class you actually define as the generic type to the BaseClass/ChildClass. Since the code expects the type to be a type which conforms to the protocol.
There are two ways you can go with your code, depending what you want to achieve with your code (you didn't tell us).
The simple case: you just want to be able to assign an object that confirms to ChildProtocol to myVar.
Solution: don't override myVar. Just use it in ChildClass. You can do this by design of the language Swift. It is one of the basics of object oriented languages.
Second case: you not only want to enable assigning instances of ChildProtocol, you also want to disable to be able to assign instances of BaseProtocol.
If you want to do this, use the Generics solution, provided here in the answers section.
If you are unsure, the simple case is correct for you.
Gerd