Share implementations with protocols - ios

I have two presenters: FirstPresenter and SecondPresenter. FirstPresenter conform to protocol PresenterProtocol. SecondPresenter needs to use all functions from FirstPresenter but with two additional.
protocol PresenterProtocol: class {
func one()
func two()
func third()
}
class FirstPresenter: PresenterProtocol {
func one() {
// do something
}
func two() {
// do something
}
func third() {
// do something
}
}
And then I have SecondPresenter and I need to use exactly the same implementation from FirstPresenter (but I want to avoid inheritance, I want do it with protocols)
class SecondPresenter: PresenterProtocols {
var firstPresenter: PresenterProtocol = FirstPresenter()
func one() {
firstPresenter.one()
// do something
}
func two() {
firstPresenter.two()
// do something
}
func third() {
firstPresenter.third()
// do something
}
func additionalFunction() {
// do something more
}
}
I am not sure if calling firstpresenter function is a good way to solve this problem, because it's just rewriting. I wonder also to use default implementation. What's the best way to share functionalities?

Your code doesn't actually rely on the methods you define, so they don't need to be requirements. They're extensions. As written, your code would be:
// This is where *requirements* go. Not shared code.
protocol PresenterProtocol: class {}
// This is your shared code
extension PresenterProtocol {
func one() {
// do something
}
func two() {
// do something
}
func third() {
// do something
}
}
// And FirstPresenter needs nothing else
class FirstPresenter: PresenterProtocol {}
// SecondPresenter gets those, and also has other things
class SecondPresenter: PresenterProtocols {
func additionalFunction() {
// do something more
}
}
Now, I'm betting that one() actually has some requirements. It needs its implementers to provide something. Those are what go in your PresenterProtocol. For example:
extension PresenterProtocol {
func one() {
doFirstThing() // Something the implementer must do
doSecondThing() // Something the implementer must do
}
}
In that case, you'd add those as requirements:
protocol PresenterProtocol {
func doFirstThing()
func doSecondThing()
}
And if there were a default way to do it that some implementers might override, then you'd provide a default implementation. Or you can just have all implementers provide it directly. Or you might not have any requirements at all.

Having a parent class is the better implementation as far as I see. But, if you don't want to, swift protocols have a nifty trick: the protocols can be extended.
Let me demonstrate using your code,
protocol PresenterProtocol: class {
func one()
func two()
func third()
}
// Adding the extenstion/default implementation
extension PresenterProtocol {
func one() {
print("one was pressed")
}
func two() {
print("two was pressed")
}
func third() {
print("third was pressed")
}
}
This way, any class conforming to PresenterProtocol will use the so-called "default implementation" (which is another way to say protocol extensions) unless you override the method in the class.
So your usage will look something like the following where you don't need to implement the 3 methods all over again.
class SecondPresenter: PresenterProtocol {
// Calling default implementations
func someFunction() {
one()
two()
third()
}
}
.
.
.
class FirstPresenter: PresenterProtocol {
func someFunction() {
one()
two()
third()
}
}
If you want more help learning, I would highly suggest reading the HackingWithSwift Tutorial

Related

SOLID principles in mvp architecture

I use model view presenter architecture in my app and I wonder what's better for respect solid principles and reusability.
So I have 4 classes: View Controller, Presenter, Model and Service. But I have a doubt in connection between presenter and service. I am not sure if I don't break single responsibility principle.
Presenter:
class WorkoutPresenter() {
// some code
let workoutSettingsService = WorkoutSettingsService()
func changeUnitFromKGtoLBInHistory() {
workoutSettingsService.changeUnitFromKGtoLBInHistory()
}
func changeUnitFromLBtoKGInHistory() {
workoutSettingsService.firstFunction()
}
func changeUnitFromKGtoLBInCalendar() {
workoutSettingsService.secondFunction()
}
}
class WorkoutSettingService {
func firstFunction() {
// some code
}
func secondFunction() {
// some code
}
func thirdFunction() {
// some code
}
}
Now workout service has 3 responsibilities (first, second and third function)
Or maybe better option would be create different class for each function and then call them in WorkoutService, something like:
class WorkoutSettingService {
let firstFunctionClass: FirstFunctionClass
let secondFunctionClass: SecondFunctionClass
let thirdFunction: ThirdFunctionClass
init(firstFunctionClassClass: FirstFunction, secondFunctionClass: SecondFunctionClass, thirdFunctionClass: ThirdFunctionClass) {
self.firstFunctionClass = firstFunction
self.secondFunctionClass = secondFunction
self.thirdFunctionClass = thirdFunction
}
func firstFunctionCall() {
firstFunctionClass.function()
}
func secondFunctionCall() {
secondFunctionClass.function()
}
func thirdFunctionCall() {
thirdFunctionClass.function()
}
}
And then call it in Presenter like before. Or maybe better than accessing to this new three class is create a protocols and set delegates from service to this new specific classes?
I hope you understand what my problem is. If you have other idea how to connect presenter with service in clean way, go ahead.
The cleaner approach in my opinion would be to introduce protocols to your service class and segregate the responsibilities.
To make the example simpler, I am going to assume that func changeUnitFromKGtoLBInHistory() and func changeUnitFromLBtoKGInHistory() have to invoke a service with respect to some history data and the func changeUnitFromKGtoLBInCalendar() has to invoke current calendar data.
First we introduce 2 protocols to do that
protocol InHistoryServiceProtocol {
func firstFunction()
func secondFunction()
}
protocol InCalendatServiceProtocol {
func thirdFunction()
}
Then we update the class WorkoutSettingService to conform to protocol as below:
class WorkoutSettingService: InHistoryServiceProtocol, InCalendatServiceProtocol {
func firstFunction() {
// some code
}
func secondFunction() {
// some code
}
func thirdFunction() {
// some code
}
}
Now we use protocol composition to gracefully handle the service class in the presenter
class WorkoutPresenter {
// some code
typealias WorkoutServiceProtocols = InHistoryServiceProtocol & InCalendatServiceProtocol
let workoutSettingsService: WorkoutServiceProtocols = WorkoutSettingService()
func changeUnitFromKGtoLBInHistory() {
workoutSettingsService.firstFunction()
}
func changeUnitFromLBtoKGInHistory() {
workoutSettingsService.secondFunction()
}
func changeUnitFromKGtoLBInCalendar() {
workoutSettingsService.thirdFunction()
}
}
This way you have the flexibility to add/remove responsibilities in the Work out service class respecting the SOLID principles. It also becomes easy to mock the data and inject into presenter for testing.

Call a method with dynamic class name in swift

How can we call class functions with a dynamic class name?
Assume the following example where I have two class with methods with same signature
class Foo{
class func doSomething()
}
class Foobar {
class func doSomething()
}
class ActualWork{
//call following method with a variable type so that it accepts dynamic class name
func callDynamicClassMethod(x: dynamicClass)
x.doSomething()
}
How can this be implemented so that x accepts values at run time
Edit: Sorry, I missed to mention that I was looking for any other ways other than protocol oriented approach. This is more of an exploratory question to explore if there is a more direct approach/pods/libraries to achieve this.
I liked this question, because it made me to think a lit'bit outside of the box.
I'll answer it, by dividing it into a few parts.
First
call class functions
Class function is basically a Type methods, which can be achieved using the static word inside the class context.
Taking that into account, you can get a simple solution, using protocol and passing the class reference (conforming to that protocol) like this:
protocol Aaa{
static func doSomething();
}
class Foo : Aaa{
static func doSomething() {
print("Foo doing something");
}
}
class FooBar : Aaa{
static func doSomething() {
print("FooBar doing something");
}
}
class ActualWork{
//Using class (static) method
func callDynamicClassMethod <T: Aaa> (x: T.Type) {
x.doSomething();
}
}
//This is how you can use it
func usage(){
let aw = ActualWork();
aw.callDynamicClassMethod(x: Foo.self);
aw.callDynamicClassMethod(x: Foo.self);
}
Second
In case you don't really need the method on the class context, you may consider using instance methods. In that case the solution would be even simpler, like this:
protocol Bbb{
func doSomething();
}
class Bar : Bbb{
func doSomething() {
print("Bar instance doing something");
}
}
class BarBar : Bbb{
func doSomething() {
print("BarBar instance doing something");
}
}
class ActualWork{
//Using instance (non-static) method
func callDynamicInstanceMethod <T: Bbb> (x: T){
x.doSomething();
}
}
//This is how you can use it
func usage(){
let aw = ActualWork();
aw.callDynamicInstanceMethod(x: Bar());
aw.callDynamicInstanceMethod(x: BarBar());
}
Third
If you need to use the class func syntax, as OP originally did:
class func doSomething()
You CANNOT simply use a protocol. Because protocol is not a class...
So compiler won't allow it.
But it's still possible, you can achieve that by using
Selector with NSObject.perform method
like this:
class ActualWork : NSObject{
func callDynamicClassMethod<T: NSObject>(x: T.Type, methodName: String){
x.perform(Selector(methodName));
}
}
class Ccc : NSObject{
#objc class func doSomething(){
print("Ccc class Doing something ");
}
}
class Ddd : NSObject{
#objc class func doSomething(){
print("Ccc class Doing something ");
}
#objc class func doOther(){
print("Ccc class Doing something ");
}
}
//This is how you can use it
func usage() {
let aw = ActualWork();
aw.callDynamicClassMethod(x: Ccc.self, methodName: "doSomething");
aw.callDynamicClassMethod(x: Ddd.self, methodName: "doSomething");
aw.callDynamicClassMethod(x: Ddd.self, methodName: "doOther");
}
Generics and Protocol oriented programming will do the job:
protocol Doable {
static func doSomething()
}
class Foo: Doable {
static func doSomething() {
debugPrint("Foo")
}
}
class Foobar: Doable {
static func doSomething() {
debugPrint("Foobar")
}
}
class ActualWork {
func callDynamicClassMethod<T: Doable>(x: T.Type) {
x.doSomething()
}
}
let work = ActualWork()
work.callDynamicClassMethod(x: Foo.self)
work.callDynamicClassMethod(x: Foobar.self)
you can achieve this with help of Protocol
protocol common {
static func doSomething()
}
class Foo : common{
static func doSomething() {
print("Foo")
}
}
class Foobar : common {
static func doSomething() {
print("Foobar")
}
}
class ActualWork{
//call following method with a variable type so that it accepts dynamic class name
func callDynamicClassMethod(x: common.Type) {
x.doSomething()
}
}
let fooObj : common = Foo()
let Foobarobj : common = Foobar()
let workObk = ActualWork()
workObk.callDynamicClassMethod(x:Foo.self)
workObk.callDynamicClassMethod(x:Foobar.self)
I think, there are three solutions. I shared an sample below.
Use "protocol" that has "doSomething()" function requirements.
Create a function which gets function definition as a parameter.
Use reflection. you can use EVReflection that is good Api for reflection.
sample code:
protocol FooProtocol {
static func doSomething()
}
class Foo: FooProtocol {
class func doSomething() {
print("Foo:doSomething")
}
}
class Foobar: FooProtocol {
class func doSomething() {
print("Foobar:doSomething")
}
}
class ActualWork {
func callDynamicClassMethod<T: FooProtocol>(x: T.Type) {
x.doSomething()
}
func callDynamicClassMethod(x: #autoclosure () -> Void) {
x()
}
func callDynamicClassMethod(x: () -> Void) {
x()
}
}
ActualWork().callDynamicClassMethod(x: Foo.self)
ActualWork().callDynamicClassMethod(x: Foobar.self)
print("\n")
ActualWork().callDynamicClassMethod(x: Foo.doSomething())
ActualWork().callDynamicClassMethod(x: Foobar.doSomething())
print("\n")
ActualWork().callDynamicClassMethod(x: Foo.doSomething)
ActualWork().callDynamicClassMethod(x: Foobar.doSomething)
Looks like you are searching for duck typing, and this is harder to achieve in a statically typed language (with some exceptions, listed in the linked Wikipedia page).
This is because dynamically calling a method requires knowledge about the layout of the target object, thus either inheritance of the class declaring the method, or conformance to a protocol that requires that method.
Starting with Swift 4.2, and the introduction of dynamic member lookup, there is another approach to solve your problem, however it also involves some ceremony:
// This needs to be used as base of all classes that you want to pass
// as arguments
#dynamicMemberLookup
class BaseDynamicClass {
subscript(dynamicMember member: String) -> () -> Void {
return { /* empty closure do nothing */ }
}
}
// subclasses can choose to respond to member queries any way they like
class Foo: BaseDynamicClass {
override subscript(dynamicMember member: String) -> () -> Void {
if member == "doSomething" { return doSomething }
return super[dynamicMember: member]
}
func doSomething() {
print("Dynamic from Foo")
}
}
class Bar: BaseDynamicClass {
override subscript(dynamicMember member: String) -> () -> Void {
if member == "doSomething" { return doSomething }
return super[dynamicMember: member]
}
func doSomething() {
print("Dynamic from Bar")
}
}
func test(receiver: BaseDynamicClass) {
receiver.doSomething()
}
test(receiver: Bar()) // Dynamic from Bar
To conclude, in the current Swift version there is no way to have both the argument and the method dynamic, some common ground needs to be set.

Redefine protocol functions using constraints without having to expose method

Ugly 1
protocol Persisting {
func persist()
}
extension Persisting {
func persist() { print("persisting") }
}
protocol Service {
func get()
func persistIfAble() // If I remove this, "Not able to persist" gets printed twice
}
extension Service {
func get() {
persistIfAble()
}
}
extension Service {
func persistIfAble() {
print("Not able to persist")
}
}
extension Service where Self: Persisting {
func persistIfAble() {
persist()
}
}
struct OnlyService: Service {}
struct Both: Service, Persisting {}
let both = Both()
both.get()
let onlyService = OnlyService()
onlyService.get()
print("Can now directly call `persistIfAble` which is not wanted")
onlyService.persistIfAble() // DONT WANT THIS TO BE POSSIBLE
This solution would be elegant if I could remove func persistIfAble() from protocol declaration. Because I do not want it to be exposed. However, what is really interesting is that if I remove it, then the behavior changes, then the implementation inside extension Service where Self: Persisting never gets called.
Ugly 2
protocol Persisting {
func persist()
}
extension Persisting {
func persist() { print("persisting") }
}
protocol Service {
func get()
}
extension Service {
func get() {
// Ugly solution, I do not want to cast, `Service` should not have to know about `Persisting`
if let persisting = self as? Persisting {
persisting.persist()
} else {
print("not able to persist")
}
}
}
extension Service where Self: Persisting {
func persistIfAble() {
persist()
}
}
struct OnlyService: Service {}
struct Both: Service, Persisting {}
let both = Both()
both.get()
let onlyService = OnlyService()
onlyService.get()
The code in both ugly solutions is of course an extremely simplified version of my actual scenario, where I really do not want to perform casts, because it makes the code so much more difficult to read. Even if I would change if let to guard let.
Ugly 3 (ugliest?)
protocol Persisting {
func persist()
}
extension Persisting {
func persist() { print("persisting") }
}
protocol Service {
func get()
func persistIfAble(allowed: Bool)
}
extension Service {
func get() {
persistIfAble(allowed: true)
}
}
extension Service {
func persistIfAble(allowed: Bool = false) {
guard allowed else { print("KILL APP"); return }
print("Not able to persist")
}
}
extension Service where Self: Persisting {
func persistIfAble(allowed: Bool = false) {
guard allowed else { print("BREAKING RULES"); return }
persist()
}
}
struct OnlyService: Service {}
struct Both: Service, Persisting {}
let both = Both()
both.get()
let onlyService = OnlyService()
onlyService.get()
print("Can now directly call `persistIfAble` which is not wanted")
// DONT WANT THIS TO BE POSSIBLE
onlyService.persistIfAble() // prints: "KILL APP"
What am I missing?
Where is the beautiful solution?
I wonder if maybe what you really want is to use composition of actual objects, not just interfaces (and some default implementations). Consider this: Both Persisting and Service as you've defined them really need to be implemented in concrete classes or structs, so that they can contain context about where they are accessing their data. So I'd imagine that you could skip the protocol extensions, leave the real "guts" up to concrete implementations of those protocols, and then something like your Both would be implemented like this:
struct Both: Persisting, Service {
let persisting: Persisting
let service: Service
// a default init lets you pass in concrete implementations of both of those things
func persist() {
persisting.persist()
}
func get() {
service.get()
persist()
}
This obviously doesn't give you the automatic sort of "mix-in" effect that it looks like you're trying to achieve, but OTOH it's pretty clear to understand.
How about removing one level of indirection (i.e. 'persistIfAble')?
protocol Persisting {
func persist()
}
extension Persisting {
func persist() {
print("persisting")
}
}
protocol Service {
func get()
}
extension Service where Self: Persisting {
func get() {
persist()
}
}
extension Service {
func get() {
print("Not able to persist")
}
}

1 global function or many instance functions

If there are two similar classes that need the same function. Is it better to write the function globally, or write the same function twice inside each of the classes. Ex.
Option 1: two instance functions
class A {
func buttonTapped() {
upvote(id)
}
func upvote(postID:String) {
// upvote the post
}
}
class B {
func buttonTapped() {
upvote(id)
}
func upvote(postID:String) {
// upvote the post
}
}
Option 2: one global function
class A {
func buttonTapped() {
upvote(id)
}
}
class B {
func buttonTapped() {
upvote(id)
}
}
func upvote(postID:string) {
// upvote the post
}
Or is there a better option?
I would suggest neither.
You should have a data model class and the upvote function should be part of that class.
class Post {
var postID: String
public private(set) var votes: Int
...
func upvote() {
self.votes += 1
}
}
Then you would call it as
somePost.upvote()
Someone suggested inheritance, but you should always consider composition over inheritance (more on the subject here: https://en.wikipedia.org/wiki/Composition_over_inheritance)
Maybe there are a lot of classes that could profit from an upvote method?
For instance, if you are implementing yet-another-instagram-clone, you could have Stories and Posts that could have the same interface for upvoting but it would be unwise of them to inherit from the same parent.
In this case, we could implement something like that:
protocol Votable {
func upvote()
}
extension Votable {
func upvote() {
// do upvoting
}
}
And then you can add this trait to your classes:
class A: Votable {
func buttonTapped() {
upvote(id)
}
}
class B: Votable {
func buttonTapped() {
upvote(id)
}
}
And there you go: same function implementation for both classes (or even different ones with the same interface if you want to implement other extensions to the same protocol) without class-inheritance.
Edit: As #Paulw11 pointed out, you should always go to the simpler solution in the beggining. If only Posts need an upvote method, don't mess around with inheritance or composition, implement the methods only where they're needed and then refactor accordingly with the evolution of your product.
I would create a "parent"-class with the common functions, and then let class A and B inherit from the "parent"-class. Like this:
class Parent {
func upvote(postID:String) {
// upvote the post
}
}
class A: Parent {
func buttonTapped() {
upvote(id)
}
}
class B: Parent {
func buttonTapped() {
upvote(id)
}
}

Composition rather than inheritance for shared variables

I was previously using a class that could be simplfied down to this:
class Whatever {
var someArray = [Int]()
func unchangingFunction {
print("test")
}
func functionForOverride() {}
}
I was asking of ways to improve this, and I got told to favour composition over inheritance, using something like the following:
protocol Implementation {
func functionForOverride()
}
final class Whatever {
var someArray = [Int]() // How can I access this?
let implementation: Implementation
init(implementation: Implementation) {
self.implementation = implementation
}
func unchangingFunction() {
print("test")
}
func functionForOverride() {
implementation.functionForOverride()
}
}
However, with this, I can't find a way to do anything with the someArray array:
struct Something: Implementation {
func functionForOverride() {
print(someArray) // This cannot work
}
}
With the original code I am able to access and alter someArray however I want, but with this new way, I can't think of an easy solution.
I think we should use a "real" example in order to make things clearer.
Inheritance (and why it's wrong)
We have the following classes
class Robot {
var battery = 0
func charge() {
print("⚡️")
battery += 1
}
}
class Human {
func eat() {
print("🍽")
}
}
class RobotCleaner: Robot {
func clean() {
print("💧")
}
}
class HumanCleaner: Human {
func clean() {
print("💧")
}
}
Code duplication!!!
As you can see the clean() method is duplicated in RobotCleaner and HumanCleaner. Can you find a way (using inheritance) to remove code duplication?
Ok think about that, I'll wait on the next paragraph... :)
...
Oh, here you are! There's no way to fix that with inheritance right? Well, let's see what we can do with composition.
Composition (the classic way)
Let's define the following 3 protocols and related components
protocol Robot {
mutating func charge()
}
struct RobotComponent: Robot {
var battery = 0
mutating func charge() {
print("⚡️")
battery += 1
}
}
protocol Human {
func eat()
}
struct HumanComponent: Human {
func eat() {
print("🍽")
}
}
protocol Cleaner {
func clean()
}
struct CleanerComponent: Cleaner {
func clean() {
print("💧")
}
}
Now we can build any combination of the previous 3 elements
struct RobotCleaner: Robot, Cleaner {
var robotComponent = RobotComponent()
let cleanerComponent = CleanerComponent()
mutating func charge() {
robotComponent.charge()
}
func clean() {
cleanerComponent.clean()
}
}
struct HumanCleaner: Human, Cleaner {
let humanComponent = HumanComponent()
let cleanerComponent = CleanerComponent()
func eat() {
humanComponent.eat()
}
func clean() {
cleanerComponent.clean()
}
}
Protocol Oriented Programming: Composition the Swifty way
Swift offers a very neat way of doing composition.
First of all let's define the following 3 protocols (and related extensions).
protocol Robot {
var battery: Int { get set }
}
extension Robot {
mutating func charge() {
print("⚡️")
battery += 1
}
}
protocol Human { }
extension Human {
func eat() {
print("🍽")
}
}
protocol Cleaner { }
extension Cleaner {
func clean() {
print("💧")
}
}
Now we can create a Type which has any combination of the previous 3 entities. Let's see how.
struct HumanCleaner: Human, Cleaner { }
struct RobotCleaner: Robot, Cleaner {
var battery: Int = 0
}
If 'Implementation' requires 'someArray' to do what it is intended to do, then you should have 'Implementation' require any object conforming to it to also declare 'someArray'
Like this:
protocol Implementation {
var someArray: [Int]
}
And if you know what you want to do with 'someFunction', then you could give a default implementation of it with a protocol extension like so:
extension Implementation {
func someFunction() {
//you can do some stuff with someArray here
}
}
Then when you conform to 'Implementation' you need to declare 'someArray' but not 'someFunction', unless you want to override the default function.
E.g.
class MyClass: Implementation {
var someArray: [Int]!
init() {}
}
Note that MyClass now has access to 'someFunction', which can be freely overridden in your class, and that you can add as many functions as you want to 'Implementation's extension.

Resources