1 global function or many instance functions - ios

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

Related

Share implementations with protocols

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

Accessing a Running Instance of a Class Swift

I have class A in file A and class B in file B. In class B, I want to access the running instance of class A, in order to run a function located in it. Both classes are connected to view controllers. I do not want to create a new instance of class A as in classAInstance = classA(), but rather access the instance of class A that my app is already running. Any help would be appreciated.
Here is part of my code in class A:
Class A {
func reloadTableView() {
self.CardsTableView.reloadData()
}
}
And here is part of my code in class B:
Class B {
#IBAction func saveButton(_ sender: UIButton) {
// here is where I want to call reloadTableView() from class A
}
}
The quick and dirty method I might use would be where you have some singleton where you can store the current instances of your classes.
Example:
class EnvironmentUtility {
private static var instance: EnvironmentUtility?
internal class func shared() -> EnvironmentUtility {
guard let currentInstance = instance else {
instance = EnvironmentUtility()
return instance!
}
return currentInstance
}
var myClassA: ClassA? = nil
var myClassB: ClassB? = nil
}
Then in the viewDidLoad (Or wherever else you like that a new instance is being made) of the those ViewControllers/Classes:
class ClassA: UIViewController {
…
override func viewDidLoad() {
…
EnvironmentUtility.shared().myClassA = self
}
…
}
Later in ClassB you could then:
class ClassB: UIViewController {
…
#IBAction func saveButton(_ sender: UIButton) {
EnvironmentUtility.shared().myClassA.reloadTable()
}
…
}
This isn’t the prettiest or Swifty-est way of doing it, but quick and dirty.
If you want to write a better solution I would suggest looking at the MVVM-C Swift architectural pattern (I use this pattern myself). In this architecture you will have access to a Coordinator that overseas viewController transitions and you can also track current instances of your ViewControllers/Classes in a much more elegant way.
Here is a crash course in MVVM-C: https://marcosantadev.com/mvvmc-with-swift/

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.

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