How to use multiple protocols in Swift with same protocol variables? - ios

In swift I'm implementing two protocols, GADCustomEventInterstitial and GADCustomEventBanner.
Both of these protocols require a property called delegate. delegate is a different type in each protocol, and thus a conflict arises.
class ChartBoostAdapter : NSObject, GADCustomEventInterstitial, GADCustomEventBanner, ChartboostDelegate{
var delegate:GADCustomEventInterstitialDelegate?; // Name conflict
var delegate:GADCustomEventBannerDelegate?; // Name conflict
override init(){
}
...
}

They are libraries/frameworks it's not my definition
Then obviously you cannot make the same class adopt both protocols. But you don't really need to. Just separate this functionality into two different classes, as is evidently intended by the designer of these protocols. You are supposed to have one class that adopts GADCustomEventInterstitial and has its delegate, and another class that adopts GADCustomEventBanner and has its delegate. What reason do you have for trying to force these to be one and the same class? As in all things where you are using a framework, don't fight the framework, obey it.

It is actually possible, I just encountered same situation. I had two different but kind of related protocols. In some cases I needed both to be implemented by delegate and in other cases only one and I didn't want to have two properties eg... delegate1, delegate2.
What you need to do is create another combined protocol that inherits from both protocols:
protocol ChartBoostAdapterDelegate: GADCustomEventInterstitialDelegate, GADCustomEventBannerDelegate { }
class ChartBoostAdapter : NSObject, GADCustomEventInterstitial, GADCustomEventBanner, ChartboostDelegate {
weak var delegate: ChartBoostAdapterDelegate?
override init(){
}
...
}

The simple answer is that you can't.
Maybe one protocol depends on another, in which case you would use the dependent protocol for the type of your delegate.

Note that this can be solved using Mixins (possible since Swift 2.0) if you are in a Swift-only environment. It just cannot be solved as long as you need to have the code bridged to Obj-C, as this problem is unsolvable in Obj-C. Yet that can usually be solved by a wrapper class, which I will show later on.
Let's break this down to a minimalist example:
import Foundation
#objc
protocol ProtoA {
var identifier: String { get }
}
#objc
protocol ProtoB {
var identifier: UUID { get }
}
#objc
class ClassA: NSObject, ProtoA, ProtoB {
let identifier = "ID1"
let identifier = UUID()
}
The code above will fail as no two properties can have the same name. If I only declare identifier once and make it a String, compiler will complain that ClassA does not conform to ProtoB and vice verse.
But here is Swift-only code that actually does work:
import Foundation
protocol ProtoA {
var identifier: String { get }
}
protocol ProtoB {
var identifier: UUID { get }
}
class ClassA {
let stringIdentifier = "ID1"
let uuidIdentifier = UUID()
}
extension ProtoA where Self: ClassA {
var identifier: String {
return self.stringIdentifier
}
}
extension ProtoB where Self: ClassA {
var identifier: UUID {
return self.uuidIdentifier
}
}
extension ClassA: ProtoA, ProtoB { }
Of course, you cannot do that:
let test = ClassA()
print(test.identifier)
The compiler will say ambigous use of 'identifier', as it has no idea which identifier you want to access but you can do this:
let test = ClassA()
print((test as ProtoA).identifier)
print((test as ProtoB).identifier)
and the output will be
ID1
C3F7A09B-15C2-4FEE-9AFF-0425DF66B12A
as expected.
Now to expose a ClassA instance to Obj-C, you need to wrap it:
class ClassB: NSObject {
var stringIdentifier: String { return self.wrapped.stringIdentifier }
var uuidIdentifier: UUID { return self.wrapped.uuidIdentifier }
private let wrapped: ClassA
init ( _ wrapped: ClassA )
{
self.wrapped = wrapped
}
}
extension ClassA {
var asObjCObject: ClassB { return ClassB(self) }
}
If you put it directly into the class declaration of ClassA, you could even make it a stored property, that way you don't have to recreate it ever again but that complicates everything as then ClassB may only hold a weak reference to the wrapped object, otherwise you create a retain cycle and neither of both objects will ever be freed. It's better to cache it somewhere in your Obj-C code.
And to solve your issue, one would use a similar wrapper approach by building a master class and this master class hands out two wrapper class, one conforming to GADCustomEventInterstitial and one conforming to GADCustomEventBanner but these would not have any internal state or logic, they both use the master class as storage backend and pass on all requests to this class that implements all required logic.

Related

Get only property defined in protocol causes compilation error when modifying inner property of object

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.

Swift: Store Type of implementation of Protocol in static var of protocol extension

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 }
}

Swift cast object to type and protocol at the same time

How can I cast a given object to a type and a protocol in order to call some methods that are defined as an extension
For Example:
extension Identifiable where Self: NSManagedObject, Self: JsonParseDescriptor {
func someMethod() { }
}
Now I have an object that I retrieved from Core data and I would like to cast it to the above protocols in order to call someMethod on it. I could cast to the protocols using protocol<Identifiable, JsonParseDescriptor> , but how can I include the NSManagedObejct type in it also?
Thanks
As of Swift 4, it is now possible to make mentioned cast directly without tricky workarounds. The task is accomplished similarly as we do protocol composition:
var myVar = otherVar as! (Type & Protocol)
No more need for extensions and bridge protocols.
What you're looking for it called a concrete same-type requirement. Unfortunately, it's not yet possible in Swift.
See ticket SR-1009 and SR-1447 for details. You should also checkout this answer.
In the mean-while, you can extend NSManagedObject with a dummy protocol with the methods you need:
protocol _NSManagedObject {
//the methods you want
}
extension NSManagedObject: _NSManagedObject {}
extension Identifiable where Self: _NSManagedObject, Self: JsonParseDescriptor {
func someMethod() { }
}

How can I create a Set of delegate protocol items in Swift?

Let's assume I have five UIView objects which all conform to a particular protocol. I have an object which should maintain a list of these objects, and message them all when necessary.
protocol MyProtocol: AnyObject {
func doSomething()
}
The problem is, when I go to add these UIViews to a Set variable, the compiler produces an error because MyProtocol does not conform to Hashable. I can understand the reasoning for this, can anyone think of good ways to overcome this? In the meantime I considered using NSHashTable instead, but you lose the nice enumeration features of Sets.
Updating answer to post some sample code (this is still not working)
protocol MyProtocol: class, AnyObject {
func doSomething()
}
class MyClass {
var observers: Set<MyProtocol> = Set<MyProtocol>()
}
As you are defining protocol for class so you need to write 'class' keyword before inheriting any other protocol:
protocol MyProtocol: AnyObject, Hashable{
func doSomething()
}
class MyClass<T: MyProtocol> {
var observers: Set<T> = Set<T>()
}
Change your protocol to this and it will work fine.
You can refer Apple Documentation for further details.

Override var conforming to a protocol with a var conforming to a child of the overridden var protocol

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

Resources