Swift 4 Delegates - what about more than 1 implementer? - swift

Swift 4:
Given: 1 protocol & 2 different classes that implement it, both of them are instantiated.
A third class, instantiated, needs to 'use' the functionality defined in the protocol.
How can I control which of the 'implementing' classes is called through the protocol by the third class?

first create a delegate.
protocol YourCustomDelegate {
func foo()
}
Your third class should have a delegate property like this:
class YourThirdClass {
var delegate = YourCustomDelegate? // this will be either the first or the second class.
}
The creator of the class should set the delegate.
class YourSecondClass {
init() {
thirdClass = YourThirdClass()
thirdClass.delegate = self
}
}
Them implement the protocol. I use an extension for more structured code. you could implement this in the YourSecondClass itself aswell.
extension YourSecondClass: YourCustomDelegate {
//implement the functions
func foo() {
print("Foo")
}
}
Do the same for the first class.
The class that currently uses YourThirdClass should set itself to be the delegate. If you want to use those simultaneously, add two delegate properties to YourThirdClass. However, if more than one class needs to be updated, consider using notifications.

Related

Setting comments in method from protocol

So I have a protocol setup in swift, and I'd like to add additional information in the methods (like comments) to the classes that use it
Currently its created using
protocol ImportProtocol {
var moc : NSManagedObjectContext { get set }
init(viewContext: NSManagedObjectContext)
// Various methods which aren't an issue
func importDIM()
}
extension ImportProtocol {
// Default implementation of the various methods above
// No implementation of init or importDIM methods
}
Is it possible to make it to that when it adds the importDIM methods it provides some content on the method to begin with? Currently the method is blank but I'd like to make it add with
func importDIM() {
let dim = addDIM()
// Stage 1
}
If you want to achieve this, you have to define a protocol with your methods, and an protocol extension where you can set computed vars and methods with code.
Example :
protocol ImportProtocol {
}
extension ImportProtocol {
func importDIM() {
let dim = addDIM()
// Stage 1
}
}
And then your classes that implements the protocol have also the base methods with code.
Some more documentation about that with more example :
https://cocoacasts.com/how-to-create-an-abstract-class-in-swift

Swift protocol to only implemented by specific classes

I want to create a protocol which is only adopted by a specific class and its subClassses in swift.
I know i can use protocol extensions like this
protocol PeopleProtocol: class {
}
extension PeopleProtocol where Self: People {
}
But the method that will go in my protocol will be an init method which will be implemented by a class or its subClasess and will return only some specific type of objects.
some thing like this.
protocol PeopleProtocol: class {
init() -> People
}
or i can do some thing like this
extension PeopleProtocol where Self : People {
init()
}
But there are two problems,
In the first approach if i put an init method in the protocol it don't allow me to put a return statement there like -> People in the first approach.
In the second approach i have to provide a function body in the protocol extensions, so this thing will be out of question, as i don't know what specific type to return for this general implementation.
So any suggestions how i can call an init method and do either:
Let the protocol (not protocol extension) to be implemented by only specific classe and its subClasses.
Or return an instance of a certain from protocol extension method without giving its body.
You could add a required method that you only extend for the appropriate classes.
for example:
protocol PeopleProtocol
{
var conformsToPeopleProtocol:Bool { get }
}
extension PeopleProtocol where Self:People
{
var conformsToPeopleProtocol:Bool {return true}
}
class People
{}
class Neighbours:People
{}
extension Neighbours:PeopleProtocol // this works
{}
class Doctors:People,PeopleProtocol // this also works
{}
class Dogs:PeopleProtocol // this will not compile
{}
This could easily be circumvented by a programmer who would want to, but at least it will let the compiler warn you if you try to apply the protocol to other classes.

Extending a class with instance method

I'm trying to extend the functionality of a existing type in Swift. I want to use dot syntax to call the methods on the type.
I want to say:
existingType.example.someMethod()
existingType.example.anotherMethod()
I'm currently using an extension like so:
extension ExistingType {
func someMethod() {
}
func anotherMethod() {
}
}
existingType.someMethod()
existingType.anotherMethod()
Doing this will expose too many functions. So, I want to write these methods in a class, and just extend the ExistingType to use an instance of the class. I'm not sure the right way to go about this.
if I were actually implementing the existing type, I would do the following:
struct ExistingType {
var example = Example()
}
struct Example {
func someMethod() {
}
func anotherMethod() {
}
}
Allowing me to call the methods by:
let existingType = ExistingType()
existingType.example.someMethod()
The issue is I'm not implementing the type, because it already exists. I just need to extend it.
It looks like you are trying to add another property example the existing class ExistingType and call methods of that property. You cannot add properties in extensions, though. The only way to add another property to the existing class is to subclass it.
You can create a new struct.
struct NewType {
let existingType: ExistingType
func someMethod() {
}
func anotherMethod() {
}
}

Setting a delegate generates a compile error

I want to use a strategy pattern to register a set of objects that implement a protocol. When I set this up, I get a compile error when trying to set the delegate that is part of the protocol.
For discussion purposes, I have slightly reworked the DiceGame from the Swift eBook's Delegation chapter. The changes of significance are:
protocol DiceGame - declares a delegate
class SnakesAndLadders implements DiceGame (and therefore the protocol and delegate)
class Games holds 3 instances of SnakesAndLadders as
1) a concrete class of SnakesAndLadders
2) a 'let' constant of protocol DiceGame
3) a 'var' variable of protocol DiceGame
We can set the delegate fine if we use the concrete class (snakesAndLadders). However, there is a compile error if we use 'let' to hold it as a protocol (diceGameAsLet) but it compiles if we hold the variable as a 'var' (diceGameAsVar).
It is easy to work around, however, the delegate itself never changes so should be held as a 'let' constant, as it is only the internal property that changes. I must not understand something (possibly subtle but significant) about protocols and how they work and should be used.
class Dice
{
func roll() -> Int
{
return 7 // always win :)
}
}
protocol DiceGame
{
// all DiceGames must work with a DiceGameDelegate
var delegate:DiceGameDelegate? {get set}
var dice: Dice {get}
func play()
}
protocol DiceGameDelegate
{
func gameDidStart( game:DiceGame )
func gameDidEnd( game:DiceGame )
}
class SnakesAndLadders:DiceGame
{
var delegate:DiceGameDelegate?
let dice = Dice()
func play()
{
delegate?.gameDidStart(self)
playGame()
delegate?.gameDidEnd(self)
}
private func playGame()
{
print("Playing the game here...")
}
}
class Games : DiceGameDelegate
{
let snakesAndLadders = SnakesAndLadders()
// hold the protocol, not the class
let diceGameAsLet:DiceGame = SnakesAndLadders()
var diceGameAsVar:DiceGame = SnakesAndLadders()
func setupDelegateAsClass()
{
// can assign the delegate if using the class
snakesAndLadders.delegate = self
}
func setupDelegateAsVar()
{
// if we use 'var' we can assign the delegate
diceGameAsVar.delegate = self
}
func setupDelegateAsLet()
{
// DOES NOT COMPILE - Why?
//
// We are not changing the dice game so want to use 'let', but it won't compile
// we are changing the delegate, which is declared as 'var' inside the protocol
diceGameAsLet.delegate = self
}
// MARK: - DiceGameDelegate
func gameDidStart( game:DiceGame )
{
print("Game Started")
}
func gameDidEnd( game:DiceGame )
{
print("Game Ended")
}
}
DiceGame is a heterogeneous protocol that you're using as a type; Swift will treat this type as a value type, and hence (just as for a structures), changing its mutable properties will mutate also the instance of the protocol type itself.
If you, however, add the : class keyword to the DiceGame protocol, Swift will treat it as a reference type, allowing you to mutate members of instances of it, without mutating the instance itself. Note that this will constraint the protocol as conformable to only by class types.
protocol DiceGame: class { ... }
With the addition of the above, the mutation of immutable diceGameAsLet:s properties will be allowed.
In this context, it's worth mentioning that the : class keyword is usually used to constrain protocols used as delegates (e.g., DiceGameDelegate in your example) as conformable to only by class types. With this additional constraint, the delegates can be used as types to which the delegate owner (e.g. some class) only hold a weak reference, useful in contexts where a strong reference to the delegate could create a retain cycle.
See e.g. the 2nd part of this answer for details.
The issue is that when you store something as a Protocol, even if it is a class, swift considers them to be a value type, instead of the reference type you are expecting them to be. Therefore, no part of it is allowed to be changed. Take a look at this reference for more information.

A way to inherit from multiple classes

I have two classes I want to use in my new class. The first one implements a swipe to delete and the second enables a long press gesture:
class DeleteItem: UITableViewCell {
}
class OpenDetail: UITableViewCell {
}
Since Swift doesn't allow a class to inherit from multiple classes the following example obviously won't work:
class ItemViewCell: DeleteItem, OpenDetail {
}
So in order to create ItemViewCell and having both options, I'll have to have one of the classes to inherit from each other:
class DeleteItem: UITableViewCell {
}
class OpenDetail: DeleteItem {
}
class ItemViewCell: OpenDetail {
}
The problem is, if I only want the long press gesture I'll have to create a new class without inheriting from DeleteItem. Is there a better way of doing this?
This is the perfect case for using Protocols and Protocol extension. A swift protocol is like an interface in Java for example. A protocol can define a set of functions which has to be implemented by the entities which want to conform to this protocol, moreover a protocol can define properties which has to be present in these entities too. For example:
protocol ItemDeleter {
var deletedCount: Int {get set}
func deleteItem(item: ItemType)
}
The problem is, that each entity would have to provide its own implementation of func deleteItem(item: ItemType) even if multiple entities share the same logic of deleting an item, this where a protocol extension comes in handy. For example:
extension ItemDeleter {
func deleteItem(item: ItemType) {
// logic needed to delete an item
// maybe incremented deletedCount too
deletedCount++
}
}
Then you could make your ItemViewCell conform to the ItemDeleter protocol, in this case all you need is to make sure that ItemViewCell has a property deletedCount: Int. It does not need to provide an implementation for func deleteItem(item: ItemType) as the protocol itself provides a default implementation for this function, however you can override it in your class, and the new implementation will be used. The same applies for DetailOpener protocol.