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.
Related
I tend to only put the necessities (stored properties, initializers) into my class definitions and move everything else into their own extension, kind of like an extension per logical block that I would group with // MARK: as well.
For a UIView subclass for example, I would end up with an extension for layout-related stuff, one for subscribing and handling events and so forth. In these extensions, I inevitably have to override some UIKit methods, e.g. layoutSubviews. I never noticed any issues with this approach -- until today.
Take this class hierarchy for example:
public class C: NSObject {
public func method() { print("C") }
}
public class B: C {
}
extension B {
override public func method() { print("B") }
}
public class A: B {
}
extension A {
override public func method() { print("A") }
}
(A() as A).method()
(A() as B).method()
(A() as C).method()
The output is A B C. That makes little sense to me. I read about Protocol Extensions being statically dispatched, but this ain't a protocol. This is a regular class, and I expect method calls to be dynamically dispatched at runtime. Clearly the call on C should at least be dynamically dispatched and produce C?
If I remove the inheritance from NSObject and make C a root class, the compiler complains saying declarations in extensions cannot override yet, which I read about already. But how does having NSObject as a root class change things?
Moving both overrides into their class declaration produces A A A as expected, moving only B's produces A B B, moving only A's produces C B C, the last of which makes absolutely no sense to me: not even the one statically typed to A produces the A-output any more!
Adding the dynamic keyword to the definition or an override does seem to give me the desired behavior 'from that point in the class hierarchy downwards'...
Let's change our example to something a little less constructed, what actually made me post this question:
public class B: UIView {
}
extension B {
override public func layoutSubviews() { print("B") }
}
public class A: B {
}
extension A {
override public func layoutSubviews() { print("A") }
}
(A() as A).layoutSubviews()
(A() as B).layoutSubviews()
(A() as UIView).layoutSubviews()
We now get A B A. Here I cannot make UIView's layoutSubviews dynamic by any means.
Moving both overrides into their class declaration gets us A A A again, only A's or only B's still gets us A B A. dynamic again solves my problems.
In theory I could add dynamic to all overrides I ever do but I feel like I'm doing something else wrong here.
Is it really wrong to use extensions for grouping code like I do?
Extensions cannot/should not override.
It is not possible to override functionality (like properties or methods) in extensions as documented in Apple's Swift Guide.
Extensions can add new functionality to a type, but they cannot override existing functionality.
Swift Developer Guide
The compiler is allowing you to override in the extension for compatibility with Objective-C. But it's actually violating the language directive.
😊That just reminded me of Isaac Asimov's "Three Laws of Robotics" 🤖
Extensions (syntactic sugar) define independent methods that receive their own arguments. The function that is called for i.e. layoutSubviews depends on the context the compiler knows about when the code is compiled. UIView inherits from UIResponder which inherits from NSObject so the override in the extension is permitted but should not be.
So there's nothing wrong with grouping but you should override in the class not in the extension.
Directive Notes
You can only override a superclass method i.e. load() initialize()in an extension of a subclass if the method is Objective-C compatible.
Therefore we can take a look at why it is allowing you to compile using layoutSubviews.
All Swift apps execute inside the Objective-C runtime except for when using pure Swift-only frameworks which allow for a Swift-only runtime.
As we found out the Objective-C runtime generally calls two class main methods load() and initialize() automatically when initializing classes in your app’s processes.
Regarding the dynamic modifier
From the Apple Developer Library (archive.org)
You can use the dynamic modifier to require that access to members be dynamically dispatched through the Objective-C runtime.
When Swift APIs are imported by the Objective-C runtime, there are no guarantees of dynamic dispatch for properties, methods, subscripts, or initializers. The Swift compiler may still devirtualize or inline member access to optimize the performance of your code, bypassing the Objective-C runtime. 😳
So dynamic can be applied to your layoutSubviews -> UIView Class since it’s represented by Objective-C and access to that member is always used using the Objective-C runtime.
That's why the compiler allowing you to use override and dynamic.
One of the goals of Swift is static dispatching, or rather the reduction of dynamic dispatching. Obj-C however is a very dynamic language. The situation you're seeing is borne out of the link between the 2 languages and the way they work together. It shouldn't really compile.
One of the main points about extensions is that they are for extending, not for replacing / overriding. It's clear from both the name and the documentation that this is the intention. Indeed if you take out the link to Obj-C from your code (remove NSObject as the superclass) it won't compile.
So, the compiler is trying to decide what it can statically dispatch and what it has to dynamically dispatch, and it's falling through a gap because of the Obj-C link in your code. The reason dynamic 'works' is because it's forcing Obj-C linking on everything so it's all always dynamic.
So, it isn't wrong to use extensions for grouping, that's great, but it is wrong to override in extensions. Any overrides should be in the main class itself, and call out to extension points.
There is a way to achieve a clean separation of class signature and implementation (in extensions) while maintaining the ability to have overrides in subclasses. The trick is to use variables in place of the functions
If you make sure to define each subclass in a separate swift source file, you can use computed variables for the overrides while keeping the corresponding implementation cleanly organized in extensions. This will circumvent Swift's "rules" and will make your class's API/signature neatly organized in one place:
// ---------- BaseClass.swift -------------
public class BaseClass
{
public var method1:(Int) -> String { return doMethod1 }
public init() {}
}
// the extension could also be in a separate file
extension BaseClass
{
private func doMethod1(param:Int) -> String { return "BaseClass \(param)" }
}
...
// ---------- ClassA.swift ----------
public class A:BaseClass
{
override public var method1:(Int) -> String { return doMethod1 }
}
// this extension can be in a separate file but not in the same
// file as the BaseClass extension that defines its doMethod1 implementation
extension A
{
private func doMethod1(param:Int) -> String
{
return "A \(param) added to \(super.method1(param))"
}
}
...
// ---------- ClassB.swift ----------
public class B:A
{
override public var method1:(Int) -> String { return doMethod1 }
}
extension B
{
private func doMethod1(param:Int) -> String
{
return "B \(param) added to \(super.method1(param))"
}
}
Each class's extension are able to use the same method names for the implementation because they are private and not visible to each other (as long as they are in separate files).
As you can see inheritance (using the variable name) works properly using super.variablename
BaseClass().method1(123) --> "BaseClass 123"
A().method1(123) --> "A 123 added to BaseClass 123"
B().method1(123) --> "B 123 added to A 123 added to BaseClass 123"
(B() as A).method1(123) --> "B 123 added to A 123 added to BaseClass 123"
(B() as BaseClass).method1(123) --> "B 123 added to A 123 added to BaseClass 123"
This answer it not aimed at the OP, other than the fact that I felt inspired to respond by his statement, "I tend to only put the necessities (stored properties, initializers) into my class definitions and move everything else into their own extension ...". I'm primarily a C# programmer, and in C# one can use partial classes for this purpose. For example, Visual Studio places the UI-related stuff in a separate source file using a partial class, and leaves your main source file uncluttered so you don't have that distraction.
If you search for "swift partial class" you'll find various links where Swift adherents say that Swift doesn't need partial classes because you can use extensions. Interestingly, if you type "swift extension" into the Google search field, its first search suggestion is "swift extension override", and at the moment this Stack Overflow question is the first hit. I take that to mean that problems with (lack of) override capabilities are the most searched-for topic related to Swift extensions, and highlights the fact that Swift extensions can't possibly replace partial classes, at least if you use derived classes in your programming.
Anyway, to cut a long-winded introduction short, I ran into this problem in a situation where I wanted to move some boilerplate / baggage methods out of the main source files for Swift classes that my C#-to-Swift program was generating. After running into the problem of no override allowed for these methods after moving them to extensions, I ended up implementing the following simple-minded workaround. The main Swift source files still contain some tiny stub methods that call the real methods in the extension files, and these extension methods are given unique names to avoid the override problem.
public protocol PCopierSerializable {
static func getFieldTable(mCopier : MCopier) -> FieldTable
static func createObject(initTable : [Int : Any?]) -> Any
func doSerialization(mCopier : MCopier)
}
.
public class SimpleClass : PCopierSerializable {
public var aMember : Int32
public init(
aMember : Int32
) {
self.aMember = aMember
}
public class func getFieldTable(mCopier : MCopier) -> FieldTable {
return getFieldTable_SimpleClass(mCopier: mCopier)
}
public class func createObject(initTable : [Int : Any?]) -> Any {
return createObject_SimpleClass(initTable: initTable)
}
public func doSerialization(mCopier : MCopier) {
doSerialization_SimpleClass(mCopier: mCopier)
}
}
.
extension SimpleClass {
class func getFieldTable_SimpleClass(mCopier : MCopier) -> FieldTable {
var fieldTable : FieldTable = [ : ]
fieldTable[376442881] = { () in try mCopier.getInt32A() } // aMember
return fieldTable
}
class func createObject_SimpleClass(initTable : [Int : Any?]) -> Any {
return SimpleClass(
aMember: initTable[376442881] as! Int32
)
}
func doSerialization_SimpleClass(mCopier : MCopier) {
mCopier.writeBinaryObjectHeader(367620, 1)
mCopier.serializeProperty(376442881, .eInt32, { () in mCopier.putInt32(aMember) } )
}
}
.
public class DerivedClass : SimpleClass {
public var aNewMember : Int32
public init(
aNewMember : Int32,
aMember : Int32
) {
self.aNewMember = aNewMember
super.init(
aMember: aMember
)
}
public class override func getFieldTable(mCopier : MCopier) -> FieldTable {
return getFieldTable_DerivedClass(mCopier: mCopier)
}
public class override func createObject(initTable : [Int : Any?]) -> Any {
return createObject_DerivedClass(initTable: initTable)
}
public override func doSerialization(mCopier : MCopier) {
doSerialization_DerivedClass(mCopier: mCopier)
}
}
.
extension DerivedClass {
class func getFieldTable_DerivedClass(mCopier : MCopier) -> FieldTable {
var fieldTable : FieldTable = [ : ]
fieldTable[376443905] = { () in try mCopier.getInt32A() } // aNewMember
fieldTable[376442881] = { () in try mCopier.getInt32A() } // aMember
return fieldTable
}
class func createObject_DerivedClass(initTable : [Int : Any?]) -> Any {
return DerivedClass(
aNewMember: initTable[376443905] as! Int32,
aMember: initTable[376442881] as! Int32
)
}
func doSerialization_DerivedClass(mCopier : MCopier) {
mCopier.writeBinaryObjectHeader(367621, 2)
mCopier.serializeProperty(376443905, .eInt32, { () in mCopier.putInt32(aNewMember) } )
mCopier.serializeProperty(376442881, .eInt32, { () in mCopier.putInt32(aMember) } )
}
}
Like I said in my introduction, this doesn't really answer the OP's question, but I'm hoping this simple-minded workaround might be helpful to others who wish to move methods from the main source files to extension files and run into the no-override problem.
Use POP (Protocol-Oriented Programming) to override functions in extensions.
protocol AProtocol {
func aFunction()
}
extension AProtocol {
func aFunction() {
print("empty")
}
}
class AClass: AProtocol {
}
extension AClass {
func aFunction() {
print("not empty")
}
}
let cls = AClass()
cls.aFunction()
Just wanted to add that for Objective-C classes, two separate categories can end up overwriting the same method, and it this case... well... unexpected things can happen.
The Objective-C runtime doesn't make any guarantees about which extension will be used, as described by Apple here:
If the name of a method declared in a category is the same as a method in the original class, or a method in another category on the same class (or even a superclass), the behavior is undefined as to which method implementation is used at runtime. This is less likely to be an issue if you’re using categories with your own classes, but can cause problems when using categories to add methods to standard Cocoa or Cocoa Touch classes.
It's a good thing Swift prohibits this for pure Swift classes, since this kind of overly-dynamic behaviour is a potential source of hard to detect and investigate bugs.
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
}
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 :)
I want to define a static variable on a class using Swift 2 that is a NSLock.
After researching I discovered that I have to use a struct, in something like this:
class Entity: NSManagedObject {
struct Mechanism {
static let lock = NSLock()
}
func myFunction -> NSArray {
Mechanism.lock.lock()
// do something
Mechanism.lock.unlock()
}
}
Will this work like C? I mean, the first time Mechanism is used a static lock constant will be created and subsequent calls will use the same constant?
I feel that this is not correct because the line
static let lock = NSLock()
is initializing a NSLock. So it will initialize a new one every time.
If this was not swift I would do like this:
static NSLock *lock;
if (!lock) {
lock = ... initialize
}
How do I do the equivalent in Swift 2?
You said that "after researching, I discovered that I have to use a struct [to get a static]." You then go on to ask whether it really is a static a how it changes in Swift 2.0.
So, a couple of observations:
Yes, this static within a struct pattern will achieve the desired behavior, that only one NSLock will be instantiated.
The significant change in the language was in Swift 1.2 (not 2.0), which now allows static variables, eliminating the need for the struct altogether:
class Entity: NSManagedObject {
static let lock = NSLock()
func myFunction() -> NSArray {
Entity.lock.lock()
// do something
Entity.lock.unlock()
}
}
Seriously, nobody uses NSLock on MacOS X or iOS. In Objective C, you use #synchronized. In Swift, you use a global function like this:
func Synchronized (obj: AnyObject, _ block: dispatch_block_t)
{
objc_sync_enter (obj)
block ()
objc_sync_exit (obj)
}
First, this uses a recursive lock. That alone will safe you gazillions of headaches. Second, it works much more fine grained, with a lock for one specific object. To use:
func myFunction() -> NSArray {
Synchronized(someObject) {
// Stuff to do.
}
}