A WWDC 2015 session video describes the idea of Protocol-Oriented Programming, and I want to adopt this technique in my future apps. I've been playing around with Swift 2.0 for the last couple of days in order to understand this new approach, and am stuck at trying to make it work with the Delegate Pattern.
I have two protocols that define the basic structure of the interesting part of my project (the example code is nonsense but describes the problem):
1) A delegation protocol that makes accessible some information, similar to UITableViewController's dataSource protocol:
protocol ValueProvider {
var value: Int { get }
}
2) An interface protocol of the entity that does something with the information from above (here's where the idea of a "Protocol-First" approach comes into play):
protocol DataProcessor {
var provider: ValueProvider { get }
func process() -> Int
}
Regarding the actual implementation of the data processor, I can now choose between enums, structs, and classes. There are several different abstraction levels of how I want to process the information, therefore classes appear to fit best (however I don't want to make this an ultimate decision, as it might change in future use cases). I can define a base processor class, on top of which I can build several case-specific processors (not possible with structs and enums):
class BaseDataProcessor: DataProcessor {
let provider: ValueProvider
init(provider: ValueProvider) {
self.provider = provider
}
func process() -> Int {
return provider.value + 100
}
}
class SpecificDataProcessor: BaseDataProcessor {
override func process() -> Int {
return super.process() + 200
}
}
Up to here everything works like a charm. However, in reality the specific data processors are tightly bound to the values that are processed (as opposed to the base processor, for which this is not true), such that I want to integrate the ValueProvider directly into the subclass (for comparison: often, UITableViewControllers are their own dataSource and delegate).
First I thought of adding a protocol extension with a default implementation:
extension DataProcessor where Self: ValueProvider {
var provider: ValueProvider { return self }
}
This would probably work if I did not have the BaseDataProcessor class that I don't want to make value-bound. However, subclasses that inherit from BaseDataProcessor and adopt ValueProvider seem to override that implementation internally, so this is not an option.
I continued experimenting and ended up with this:
class BaseDataProcessor: DataProcessor {
// Yes, that's ugly, but I need this 'var' construct so I can override it later
private var _provider: ValueProvider!
var provider: ValueProvider { return _provider }
func process() -> Int {
return provider.value + 10
}
}
class SpecificDataProcessor: BaseDataProcessor, ValueProvider {
let value = 1234
override var provider: ValueProvider { return self }
override func process() -> Int {
return super.process() + 100
}
}
Which compiles and at first glance appears to do what I want. However, this is not a solution as it produces a reference cycle, which can be seen in a Swift playground:
weak var p: SpecificDataProcessor!
autoreleasepool {
p = SpecificDataProcessor()
p.process()
}
p // <-- not nil, hence reference cycle!
Another option might be to add class constraints to the protocol definitions. However, this would break the POP approach as I understand it.
Concluding, I think my question boils down to the following: How do you make Protocol Oriented Programming and the Delegate Pattern work together without restricting yourself to class constraints during protocol design?
It turns out that using autoreleasepool in Playgrounds is not suited to proof reference cycles. In fact, there is no reference cycle in the code, as can be seen when the code is run as a CommandLine app. The question still stands whether this is the best approach. It works but looks slightly hacky.
Also, I'm not too happy with the initialization of BaseDataProcessors and SpecificDataProcessors. BaseDataProcessors should not know any implementation detail of the sub classes w.r.t. valueProvider, and subclasses should be discreet about themselves being the valueProvider.
For now, I have solved the initialization problem as follows:
class BaseDataProcessor: DataProcessor {
private var provider_: ValueProvider! // Not great but necessary for the 'var' construct
var provider: ValueProvider { return provider_ }
init(provider: ValueProvider!) {
provider_ = provider
}
func process() -> Int {
return provider.value + 10
}
}
class SpecificDataProcessor: BaseDataProcessor, ValueProvider {
override var provider: ValueProvider { return self } // provider_ is not needed any longer
// Hide the init method that takes a ValueProvider
private init(_: ValueProvider!) {
super.init(provider: nil)
}
// Provide a clean init method
init() {
super.init(provider: nil)
// I cannot set provider_ = self, because provider_ is strong. Can't make it weak either
// because in BaseDataProcessor it's not clear whether it is of reference or value type
}
let value = 1234
}
If you have a better idea, please let me know :)
Related
Given that I have a function that does not need to share and store state; should I use a static class/struct/enum to hold the function? I have read in many places that it is a bad design to use static functions to hold code, as static function do not adhere to the SOLID principles and are considered procedural code. Testability seems to be there as I can isolate the parent class with the injected static Enums by injecting mock static enums.
E.g. I can encapsulate and have polymorphism by using protocols for static functions:
Static Protocol Approach
enum StaticEnum: TestProtocol {
static func staticMethod() {
print("hello")
}
}
enum StaticEnum2: TestProtocol {
static func staticMethod() {
print("hello2")
}
}
protocol TestProtocol {
static func staticMethod()
}
class TestClass {
let staticTypes: [TestProtocol.Type]
init (staticTypes: [TestProtocol.Type]) {
self.staticTypes = staticTypes
}
}
class TestFactory {
func makeTestClass() -> TestClass {
return TestClass(staticTypes: [StaticEnum.self, StaticEnum2.self])
}
}
vs
Object Oriented Approach
class InstanceClass: TestProtocol {
func instanceMethod() {
print("hello")
}
}
class InstanceClass2: TestProtocol {
func instanceMethod() {
print("hello2")
}
}
protocol TestProtocol {
func instanceMethod()
}
class TestClass {
let instances: [TestProtocol]
init (instances: [TestProtocol]) {
self.instances = instances
}
}
class TestFactory {
func makeTestClass() -> TestClass {
return TestClass(instances: [InstanceClass(), InstanceClass2()])
}
}
The static version still allows for protocol polymorphism as you can have multiple enums adhere to the static protocols. Furthermore no initialisation is needed after the first dispatch call to create the static function. Is there any drawback in using the Static Protocol approach?
Why static methods can violate SOLID
I have read in many places that it is a bad design to use static functions to hold code, as static function do not adhere to the SOLID principles and are considered procedural code.
I suspect you've read about this in the context of other languages, such as Java, which I'll use as a concrete example for simplicity.
Indeed, this is true for Java. But rather than a hand-wavy quote about why static is the boogeyman, it's good to understand the precise details.
In Java, static methods are truly static. They're really no different than a global function that just happens to be namespaced to a class.
As such, it violated the dependency inversion principle (the "D" in SOLID). Any usage of a static method in Java is a case where the calling code is relying on a concretion (that particular implementation of the method) and not an abstraction (an interface that describes that method), making polymorphism impossible. Essentially there's no way to substitute one implementation for another.
... but not in Swift.
This is just not the case in Swift.
In Swift, when a type conforms to a protocol, instances of that type are guaranteed to meet the protocols requirements for instance methods, properties and subscripts, just like Java.
But as you've discovered, when a Swift type conforms to a protocol, the type itself is guaranteed to meet the protocol requirements for static methods, static properties, static subscripts and initializers.
This goes a step beyond what Java's interfaces can express.
I like to visualize it by thinking of each Swift protocol as acting as if it were (up to) two conventional Java interfaces in one.
When you have:
protocol MyProtocol {
static func myStaticMethod() {}
func myInstanceMethod() {}
}
struct MyImplementation: MyProtocol {
static func myStaticMethod() {}
func myInstanceMethod() {}
}
It behaves as if you had (psuedo-code):
interface MyProtocol_MetaHalf {
static func myStaticMethod() {}
}
interface MyProtocol_InstancedHalf {
func myInstanceMethod() {}
}
struct MyImplementation.Type: MyProtocol_MetaHalf {
static func myStaticMethod() {}
}
struct MyImplementation: MyProtocol_InstancedHalf {
func myInstanceMethod() {}
}
You might recognize this as being eerily similar to the way Java interfaces are often used. You'd often have a pair, interface Foo, and interface FooFactory. I argue that the prevalence of "Factory" classes in Java stems from their interfaces' inability to express static requirements, thus what could have been a static method has to be instead split off into an instance method on a new class.
As you've also seen, Swift's static methods can satisfy protocol requirements and they can be polymorphically called. Example:
protocol MyProtocol {
static func staticMethod()
}
struct Imp1: MyProtocol {
static func staticMethod() { print("Imp1") }
}
struct Imp2: MyProtocol {
static func staticMethod() { print("Imp1") }
}
let someImplementation: MyProtocol.Type = Imp1.self
// A polymorphic call to a static method
someImplementation.staticMethod()
Thus, you can see that the testability issue with Java interfaces doesn't translate to Swift's interfaces. You can easily implement a new mock type that conforms to a protocol with a static requirement, and provide a mock implementation to the static method.
All that is to say: What you proposed is possible (well clearly, you provided a working demonstration). But it begs the question: why would you do it?
Why use metatypes when types will do?
Having a type system that supports both types (which describe the methods of their instances, the objects) and metatypes (which describes the methods of their instances, the types) can be useful for expressing ideas like "I have a widget, and it's paired with a thing that makes widgets, here's how the two go together into one protocol/class/struct."
But what you've done is essentially ... dial up the "meta level" by one. In your example, you use types instead of objects, and metatypes instead of types. But fundamentally, you haven't achieved anything that can't already be expressed more easily/clear using the typical pairing of objects + types.
Here's how I would express what you wrote:
struct Implementation1: TestProtocol {
func instanceMethod() {
print("hello")
}
}
struct Implementation2: TestProtocol {
func instanceMethod() {
print("hello2")
}
}
protocol TestProtocol {
func instanceMethod()
}
class TestClass {
let implementations: [TestProtocol]
init(implementations: [TestProtocol]) {
self.implementations = implementations
}
}
class TestFactory {
func makeTestClass() -> TestClass {
return TestClass(implementations: [Implementation1(), Implementation2()])
}
}
Given that I have a function that does not need to share and store state
They might not need that today, but maybe they will need it in the future. Or maybe not. For now, I just modelled the implementations using empty structs.
This is probably a good time to emphasize there's a difference between "I only need one object of this", vs "I'm adamant I only ever want exactly one object of this".
That might sound silly/obvious, but you'd be surprised how frequently post here asking about how they can be two instances of a singleton :)
If you're totally adamant that you'll never need state, then perhaps you enforce the one-objectness constraint with a singleton:
struct Implementation1: TestProtocol {
public static var shared: Self { Self() }
private init() {}
func instanceMethod() {
print("hello")
}
}
I am trying to use factory pattern in swift, and give is my code
I have two protocols
protocol MyProtocol1{
func callLoginAPI()
}
protocol MyProtocol2{
func callPaymentAPI()
}
I have two structures which conform to these protocols
struct MyManager1: MyProtocol1{
func callLoginAPI()
{
debugPrint("Inisde--MyManager1 and ready to call an Login API")
}
}
struct MyManager2: MyProtocol2{
func callPaymentAPI()
{
debugPrint("Inisde--MyManager2 and ready to call Payment API")
}
}
I want to use the factory pattern to create the instance of Manager by passing the Protocol and returning a concrete object of the struct that conforms to that protocol
Example: ManagerFactory.create(MyProtocol1) --> should give me instance of MyManager1 and doing ManagerFactory.create(MyProtocol2) --> should give me instance of MyManager2
I assume that this may not work as I am asking for a concrete type at runtime, so I ended up doing something like this
protocol IManagerFactory{
func getMyManager1() -> MyProtocol1
func getMyManager2() -> MyProtocol2
}
struct ManagerFactory: IManagerFactory
{
func getMyManager1() -> MyProtocol1 {
return MyManager1()
}
func getMyManager2() -> MyProtocol2 {
return MyManager2()
}
}
But I am curious if what I am trying to do in the example is achievable, I am using swift 4.2.
I have seen other examples but all of them have the same protocol which they conform to like rectangle, square and circle conform to same protocol shape.
In my case, I have two separate protocols which do completely different things so is that even possible what I am trying to do in the example? OR the way I ended up with is the only way to go about it.
Please suggest what is the best possible approach.
First, I'm very suspicious of a "manager" that is a value (a struct) rather than an instance (a class). Do you really mean to be using structs and protocols here at all? Structs have no identity; two structs with the same properties must be completely interchangeable for each other, and things like that don't usually get named "manager."
What you're describing is certainly writeable. It's just kind of useless. Here's how you write it:
struct ManagerFactory {
static func create(_ type: MyProtocol1.Protocol) -> MyProtocol1 {
return MyManager1()
}
static func create(_ type: MyProtocol2.Protocol) -> MyProtocol2 {
return MyManager2()
}
}
let mgr1 = ManagerFactory.create(MyProtocol1.self)
let mgr2 = ManagerFactory.create(MyProtocol2.self)
But this is just an elaborate way to use method overloading to replace names.
What you seem to want is a single method, but what would its return type be? Even in C#, I don't think this is writable without adding nasty downcasts. (This is the point you and paulw11 discuss in the comments.) This isn't a limitation of Swift; it's a fundamental characteristic of types. Even in JavaScript, you'd need to know what you expect to get back or else you won't know what methods you can call on it (it's just you track that expectation in your head and docs rather than in the compiler and code).
You seem to have created a lot of protocols here, and I'm betting they mostly have exactly one implementation. That's bad Swift. Don't create protocols until you have a specific need for one. Don't create attractions for fun. They will burn you very quickly.
If your protocols really look like this, and you really have different implementations of these methods (i.e. don't do this if there is only one implementation of MyProtocol1 "just in case"), what you really want are functions:
struct API {
let login: () -> Void
let payment: () -> Void
}
let myAPI = API(login: myLoginFunction, payment: myPaymentFunction)
This will let you create different APIs if you need them. But again, only if you need this flexibility. If not, just use classes for instances, and structs for values, and avoid protocols until you have at least 2, and better 3, implementations in your program.
Suggest a swifty option:
protocol Manager {
// a generic protocol for all managers
}
protocol BadManager: Manager {
// properties and behaviour of BadManager
mutating func noBonus()
}
protocol GoodManager: Manager {
// properties and behaviour of GoodManager
mutating func bigBonus()
}
protocol ManagerFactory {
associatedtype Manager
mutating func createManager() -> Manager
}
struct gm: GoodManager {
mutating func bigBonus() {
print("tons of cookies & coffee")
}
}
struct bm: BadManager {
mutating func noBonus() {
print("all fired")
}
}
enum ManagerCreator<Manager>: ManagerFactory {
func createManager() -> Manager {
switch self {
case .goodManager:
return gm() as! Manager
case .badManager:
return bm() as! Manager
}
}
case goodManager
case badManager
}
Can we communicate between classes like below code instead of using delegate/protocol pattern and notification. I haven't seen any code example like this. But just curious to know why this should work or not work.
class Class1 {
var class2Obj: Class2 = Class2()
init() {
class2Obj.class1Obj = self
}
func class1Method() {
print("Parent")
}
}
class Class2 {
weak var class1Obj: Class1?
func class2Method() {
class1Obj.class1Method()
}
}
What you have here is a delegate pattern. Your delegate property is merely called class1Obj rather than the more customary delegate name. The key issue here is that you're not using a protocol, and as a result these two classes are "tightly coupled," i.e. Class2 is highly dependent upon details of the Class1 implementation. Furthermore, with these two tightly coupled classes, it's not immediately clear which methods of Class1 that Class2 might need. It makes maintenance of Class1 harder because so it's easy to accidentally make a change that breaks behavior in Class2. It also makes it hard to use Class2 in conjunction with some other class other than Class1.
Instead, you'd generally declare a protocol to precisely articulate the nature of the contract between Class2 and other object that might need to use it. The result is that the classes are less tightly coupled, i.e. Class2 needs to know nothing about the other class other than its conformance to the protocol in question. Furthermore, when editing Class1, if you declare it to conform the the protocol, the compiler will warn you when you fail to implement some required method or property.
So, with a negligible amount of work up-front, the protocol makes the code much easier to maintain. It also provides some additional flexibility whereby you may use Class2 in conjunction with something other than Class1 in the future.
Bottom line, protocols can result in code that is easier to maintain and is more flexible, with no hidden assumptions.
If you don't want to use the delegate-protocol pattern, another alternative is to use a closure, where Class1 supplies a block of code that Class2 can call. So you can do something like:
class Class1 {
var class2Obj = Class2()
init() {
class2Obj.handler = { [weak self] in // note `weak` reference which avoids strong reference cycle
self?.class1Method()
}
}
func class1Method() {
print("Parent")
}
}
class Class2 {
var handler: (() -> Void)?
func class2Method() {
handler?()
}
}
While the delegate-protocol pattern is useful when you have a rich interface between the two classes, this closure pattern when you have a very simple interface between the two classes.
Frankly, a more common permutation of the above is where the closure is more directly associated with some particular request that Class1 initiates in Class2. So, you might just make the parameter a closure to the appropriate method in Class2. Furthermore, you're often passing data back, so imagine that we're passing back an optional String:
class Class1 {
var class2Obj = Class2()
func performClass2Method() {
class2Obj.class2Method { string in
guard let string = string else { return }
self.class1Method()
}
}
func class1Method() {
print("Parent")
}
}
class Class2 {
func class2Method(completionHandler: #escaping (String?) -> Void) {
// do something which creates `string`
// when done, call the closure, passing that `string` value back
completionHandler(string)
}
}
These closure patterns a great way to do simple interfaces between objects, but also keeps the two classes very loosely coupled (i.e. Class2 has no dependencies upon Class1), much like using a protocol in the delegate pattern did. But hopefully the above closure examples illustrate a simple alternatives to the rich delegate-protocol pattern.
I have some codes in java which organized well, so it helps me manage source code as well as extend in future easily. These codes as follow
public interface IDataModel<T extends IDataModel> {
void copyData(T data);
long getUpdatedTime();
}
public abstract class AbstractDataModel<T extends IDataModel> implements IDataModel<T>{
protected long updatedTime;
public long getUpdatedTime(){
return updatedTime;
}
}
public class concreteDataA extends AbstractDataModel<concreteDataA>{
String property1;
public String getProperty1(){
return property1;
}
#override
public void copyData(concreteDataA data){
property1 = data.getProperty1();
updatedTime = data.getUpdatedTime();
}
}
Now i want to port into iOS swift 3.0. Is it possible to organize code in swift 3.0 as above? Or is there any equivalent way in swift to organize code as above? I'm quite new to swift iOS, so it makes me hard to organize source code in pattern. Thanks you.
You haven't provided much in the way of context, but it seems like you're struggling developing a "protocol-oriented" solution, as Swift folks like to call the pattern. Here are a couple of options that might solve your problem (spoiler – I think the problem is in your design):
Interface: Protocol, Abstract Class: Protocol Extension
Like #sulthan mentioned, you can certainly get to a similar place using protocols with default implementations, like so:
protocol DataModel {
mutating func copy(data: Self)
var updatedTime : Float { get }
}
extension DataModel {
var updatedTime : Float { return 0 }
}
However, you'll run into a problem when you try to implement the ConcreteDataModel since you want to specialize it to account for the property1 value that isn't mentioned in the protocol. Your options are to relax that requirement in ConcreteDataModel (aka don't do that) or use typecasting. Please note, fighting the typing system in Swift is a sure sign that your code is not idiomatic! You should see this difficulty as the language nudging you to reconsider your approach.
Use immutable data types
This is the most straight-forward answer. If what you've described above is actually a concrete example from your app, then you don't really need protocols at all. (In fact, your Java implementation is certainly over-abstracting.) Swift structs are immutable, which means that whenever you change them, you are actually changing a copy.
struct DataModel {
let updatedTime: Float
mutating func update(time: Float) {
self = DataModel(updatedTime: time)
}
}
var data1 = DataModel(updatedTime: 3)
var data2 = data1
data2.update(time: 17)
print(data1.updatedTime) // 3.0
print(data2.updatedTime) // 17.0
Model your behavior apart from your data
This is the generalized solution. From a design perspective, it's clear that you have two distinct concerns. You want something copyable, and you want something that tracks "time." Why not just let your code reflect that?
protocol Copier {
associatedtype Data
func copy(from: Data) -> Data
}
protocol Clock {
var time: Float { get }
}
class AlarmClock: Clock, Copier {
let time: Float
let alarm: Float
init(time: Float, alarm: Float) {
self.time = time
self.alarm = alarm
}
func copy(from: AlarmClock) -> AlarmClock {
return AlarmClock(time: from.time, alarm: from.alarm)
}
}
Of course, you could even go the last step and provide the default implementation for Clock.time if you really needed it.
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