I started coding in Swift only recently and I am hitting an issue. I need a tearoff mechanism for several of my swift classes and I wonder what the best way to implement that. Let me explain: I need to implement an extension for 3 of my 50+ classes. Since the code there will be rarely called by users, I am thinking of a tearoff instead of a subclass to improve memory footprint. For complex architectural reasons, a subclass would not be practical anyway. So the idea is the following: have my three classes host a TearOff? attribute, that is instantiated only when a first method of the extension is called, and call the tearoff from my classes so the code (that is pretty complex) is shared. Skeleton:
class foo1 {}
class foo2 {}
class foo3 {}
class TearOff { func method() { blablablabla } }
extension foo1 { func method() {
if nil == tearoff {
tearoff = TearOff()
}
tearoff!.method()
}
extension foo2 { func method() {
if nil == tearoff {
tearoff = TearOff()
}
tearoff!.method()
}
extension foo3 { func method() {
if nil == tearoff {
tearoff = TearOff()
}
tearoff!.method()
}
My problem is that an extension can host only methods, and not attributes, so I can't declare the tearoff as a TearOff? in the three extensions. And declaring it directly in foo1 foo2 and foo3, although always possible, is really suboptimal.
I would appreciate any help you can provide. Thanks a lot!
Related
I'm drawing a blank for some reason.. If I want to make a bunch of objects from a class, but I want each instance to have its own unique implementation of a certain method, how would I do this?
For example:
class MyClass {
var name: String
func doSomething() {
// Each object would have custom implementation of this method, here.
}
}
Do I provide each object with its own closure during initialization, and then call that closure in the doSomething() method? I'm trying to figure out the correct or "Swiftly" way to do this. I'm also thinking along the lines of something with protocols, but I can't seem to figure out how to go about this.
I think there're many ways to do it.
In case of Base class + some sub-classes (e.g. Animal, subclassed by Dog, Cat, etc), you can do this:
First of all it's a good idea to define a protocol:
protocol MyProtocol {
func doSomething()
}
Also provide a default implementation, which throws a fatal error if a class doesn't override that method:
extension MyProtocol {
func doSomething() {
fatalError("You must override me")
}
}
Now your base class confirms the protocol thanks to default implementation. But it will throw a fatal error at runtime:
class MyClass: MyProtocol {
// conformant
}
Child class, however, will run correctly as long as it overrides this function:
class MyOtherClass: MyClass {
func doSomething() {
print("Doing it!")
}
}
You could also move fatal error into base class, and not do any extension implementation.
In case of many instances of the same Class, that solution makes no sense. You can use a very simple callback design:
typealias MyDelegate = () -> Void
class MyClass {
var delegate: MyDelegate?
func doSomething() {
delegate?()
}
}
let x = MyClass()
x.delegate = {
print("do it!")
}
x.doSomething()
// Or you can use a defined function
func doIt() {
print("also doing it")
}
x.delegate = doIt
x.doSomething()
It can also be that you re looking for Strategy pattern, or Template pattern. Depends on your usage details.
Do I provide each object with its own closure during initialization, and then call that closure in the doSomething() method
Yes. That is extremely common and eminently Swifty. Incredibly miminalistic example:
struct S {
let f:()->()
func doYourThing() { f() }
}
let s = S { print("hello") }
let s2 = S { print("goodbye" )}
s.doYourThing() // hello
s2.doYourThing() // goodbye
Giving an object a settable method instance property is very, very easy and common. It doesn't have to be provided during initialization — you might set this property later on, and a lot of built-in objects work that way too.
That, after all, is all you're doing when you create a data task with dataTask(with:completionHandler:). You are creating a data task and handing it a function which it stores, and which it will call when it has performed the actual networking.
I still don't understand what is the difference when declaring a Swift protocol using inheritance:
protocol SubProtocol: SuperProtocol { ... }
or using where Self
protocol SubProtocol where Self: SuperProtocol { ... }
By doing this on these two ways the results are exactly the same, both options compile fine, and it works, SubProtocol will have the same stuff than SuperProtocol has. So what is the difference?
The only difference I can see is the semantic, one is more clear than the other (see example below). But this is my point of view and I would like to know if someone else thinks the same, or perhaps I am miss-understanding the whole thing.
Example:
protocol Progressable {
var isInProgress: Bool { get }
}
protocol Downloadable: Progressable {
func download()
}
protocol ProgressReporting where Self: Progressable {
func reportProgress() -> Bool
}
For me, Downloadable makes sense it inherits from Progressable, every download is progressable, so that is fine.
But ProgressReporting not necessary needs to inherit from Progressable, for me it would make more sense to constraint it by using where, this way the reader can know that whoever implements it, will need to conform to Progressable too (see the comments on the code below), here is when I think the semantic is different.
class MyClassA: Downloadable {
var isInProgress: Bool { return true }
func download() {}
func foo() {
/*
I have access to `self.isInProgress` because this class conforms `Downloadable`
which inherits from `Progressable`, so this makes sense
*/
_ = self.isInProgress
}
}
class MyClassB: ProgressReporting {
var isInProgress: Bool { return true }
func reportProgress() {}
func foo() {
/*
I have access to `self.isInProgress` but according to `ProgressReporting` definition,
this class should be `Progressable` which is not, at least not explicitely
*/
_ = self.isInProgress
}
}
I would apreciate if someone can explain me what are the differences 🙂
Thanks in advance.
Speaking about Swift5, there is no difference between the two forms, see Swift 5 Release notes:
Protocols can now constrain their conforming types to those that subclass a given class. Two equivalent forms are supported:
protocol MyView: UIView { /*...*/ }
protocol MyView where Self: UIView { /*...*/ }
Swift 4.2 accepted the second form, but it wasn’t fully implemented and could sometimes crash at compile time or runtime. (SR-5581) (38077232)
As I have learned from internet and Xcode you can't do something like this:
protocol Foo {}
class Bar<T: Foo> {
}
class A {
var some: Bar<Foo>! // this one
}
because types for generic variables must be concrete. How to bypass that restriction? The easiest way seems to use another protocol, for example B, then change Bar<Foo> to B, and then all the classes that inherits from Bar must implement protocol B, but it's seems not very convenient, so maybe another ways? Or maybe someone knows, would Swift support not concrete generics in future? Because as seen in Kotlin, this is not something that can be done in programming languages
I have an example, let say you want to implement Injection with a nice way.
class Injectable<T: ServiceProtocol> {
let type: ServiceProtocol.Type { return T.self }
var value: T!
}
Then use something like
class ViewModel {
let serviceA = Injectable<AbstractNetworkService>()
}
class DependencyProvider {
...
func injectDependencies(into object: AnyObject) {
// Here you would use a Mirror of object, go through every Injectable,
// and set their values.
}
}
That is nice because you can register an actual class for an AbstractNetworkService (a protocol), but Swift won't let you do that.
I have a Swift protocol defined as follows:
protocol SmartContract {
func apply(transaction :Transaction)
func addBrokenRule(_ brokenRule: BrokenRule)
var brokenRules :[BrokenRule] { get set }
}
I have an extension on SmartContract defined as follows:
extension SmartContract {
mutating func addBrokenRule(_ brokenRule :BrokenRule) {
if self.brokenRules == nil {
self.brokenRules = [BrokenRule]()
}
self.brokenRules.append(brokenRule)
}
}
I also have a class MoneyTransferContract which conforms to the protocol but does not define brokenRules. This is because I have defined the brokenRules inside the extension.
class MoneyTransferContract : SmartContract {
func apply(transaction :Transaction) { // do something here }
}
My question is how can I make sure that MoneyTransformContract conforms to the SmartContract protocol. Is there anyway to have BrokenRule available to MoneyTransformContract without defining it again and again in different SmartContracts.
john doe wrote:
Is there anyway to have BrokenRule available to MoneyTransformContract without defining it again and again in different SmartContracts.
What you want is a superclass/subclass relationship for that behavior.
class SmartContract {
func apply(transaction :Transaction) {
//implemention
}
var brokenRules: [BrokenRule] = []
func addBrokenRule(_ brokenRule :BrokenRule) {
brokenRules.append(brokenRule)
}
}
class MoneyTransferContract : SmartContract {
// Gets `brokenRules` for free from superclass.
}
class BitCoinTransferContract : SmartContract {
// Gets `brokenRules` for free from superclass.
}
If I'm understanding correctly, there is no way to do what you want. (EDIT: as Jeff notes, if you want to use inheritance as opposed to a protocol, this is possible. See his answer for how). Protocols in Swift are just lists of requirements that it is up to implementing types to properly define. Protocols generally don't have any say over the actual behavior or implementation of implementing types, and only guarantees that the properties and functions exist. Your SmartContract protocol says that every SmartContract must have a function apply(transaction:), a function addBrokenRule(_:), and a property brokenRules which can be accessed and modified.
When a type implements SmartContract it has to define each one of these. Just as you have to write out the signature to tell the compiler that you are implementing apply(transaction:), you also have to tell the compiler how the property brokenRules will be implemented. You could obtain this functionality in a somewhat useless way, by defining an extension which has brokenRules as a computed property which is essentially a no-op:
extension SmartContract {
var brokenRules: [BrokenRule] {
get { return [] }
set(newRules) { }
}
}
But this means that any implementing type which forgets to specify their own implementation for brokenRules will have a brokenRules property which always resolves to an empty array.
One reason for this is Swift's computed properties. For some implementing type, it might not make sense for brokenRules to be stored as an array--and a protocol can't force that. That's an implementation detail that a protocol author can't (and shouldn't) worry about. For instance, if BrokenRules were easily convertible to and from strings, you could imagine some class which implemented SmartContract like so:
class StringContract: SmartContract {
var ruleString: String
var brokenRules: [BrokenRule] {
get {
let stringArray = ruleString.split(separator: ",")
return stringArray.map { BrokenRule(string:String($0)) }
}
set(newRules) {
let stringArray = newRules.map { $0.stringValue }
ruleString = stringArray.joined(separator: ",")
}
}
func apply(transaction: Transaction) {
// do something here...
}
init() {
ruleString = ""
}
}
Note that we don't have to specify an implementation for addBrokenRule(_:). That's what your protocol extension gets you. By providing an implementation in the extension, you ensure that all implementing types have a default implementation of the function, and so they can choose to forego defining their own.
How can we determine if protocol conforms to a specific subtype based on user provided instances, if it's not possible this way, any alternate solutions.
API
protocol Super {}
protocol Sub: Super {} //inherited by Super protocol
class Type1: Super {} //conforms to super protocol
class Type2: Type1, Sub {} //conforms to sub protocol
inside another API class
func store(closures: [() -> Super]) {
self.closures = closures
}
when it's time to call
func go() {
for closure in closures {
var instance = closure()
if instance is Super {
//do something - system will behave differently
} else { //it's Sub
//do something else - system will behave differently
}
}
}
users of the api
class Imp1: Type1 {}
class Imp2: Type2 {}
var closures: [() -> Super] = [ { Imp1() }, { Imp2() } ]
store(closures)
my current workaround within API
func go() {
for closure in closures {
var instance = closure()
var behavior = 0
if instance as? Type2 != nil { //not so cool, should be through protocols
behavior = 1 //instead of implementations
}
if behavior == 0 { //do something within the api,
} else { //do something else within the api
}
//instance overriden method will be called
//but not important here to show, polymorphism works in here
//more concerned how the api can do something different based on the types
}
}
You are jumping through a lot of hoops to manually recreate dynamic dispatch, i.e. one of the purposes of protocols and classes. Try actually using real runtime polymorphism to solve your problem.
Take this code:
if instance is Super {
//do something
} else { //it's Sub
//do something else
}
What you are saying is, if it’s a superclass, run the superclass method, else, run the subclass. This is a bit inverted – normally when you are a subclass you want to run the subclass code not the other way around. But assuming you turn it around to the more conventional order, you are essentially describing calling a protocol’s method and expecting the appropriate implementation to get called:
(the closures aren’t really related to the question in hand so ignoring them for now)
protocol Super { func doThing() }
protocol Sub: Super { } // super is actually a bit redundant here
class Type1: Super {
func doThing() {
println("I did a super thing!")
}
}
class Type2: Sub {
func doThing() {
println("I did a sub thing!")
}
}
func doSomething(s: Super) {
s.doThing()
}
let c: [Super] = [Type1(), Type2()]
for t in c {
doSomething(t)
}
// prints “I did a super thing!”, then “I did a sub thing!"
Alternatives to consider: eliminate Sub, and have Type2 inherit from Type1. Or, since there’s no class inheritance here, you could use structs rather than classes.
Almost any time you find yourself wanting to use is?, you probably meant to use an enum. Enums allow you use to the equivalent of is? without feeling bad about it (because it isn't a problem). The reason that is? is bad OO design is that it creates a function that is closed to subtyping, while OOP itself is always open to subtyping (you should think of final as a compiler optimization, not as a fundamental part of types).
Being closed to subtyping is not a problem or a bad thing. It just requires thinking in a functional paradigm rather than an object paradigm. Enums (which are the Swift implementation of a Sum type) are exactly the tool for this, and are very often a better tool than subclassing.
enum Thing {
case Type1(... some data object(s) ...)
case Type2(... some data object(s) ...)
}
Now in go(), instead of an is? check, you switch. Not only is this not a bad thing, it's required and fully type-checked by the compiler.
(Example removes the lazy closures since they're not really part of the question.)
func go(instances: [Thing]) {
for instance in instances {
switch instance {
case Type1(let ...) { ...Type1 behaviors... }
case Type2(let ...) { ...Type2 behaviors... }
}
}
}
If you have some shared behaviors, just pull those out into a function. You're free to let your "data objects" implement certain protocols or be of specific classes if that makes things easier to pass along to shared functions. It's fine if Type2 takes associated data that happens to be a subclass of Type1.
If you come along later and add a Type3, then the compiler will warn you about every switch that fails to consider this. That's why enums are safe while is? is not.
You need objects derived from the Objective-C world to do this:
#objc protocol Super {}
#objc protocol Sub: Super {}
class Parent: NSObject, Super {}
class Child: NSObject, Sub {}
func go( closures: [() -> Super]) {
for closure in closures {
let instance = closure()
if instance is Sub { // check for Sub first, check for Super is always true
//do something
} else {
//do something else
}
}
}
Edit: Version with different method implementations:
protocol Super {
func doSomething()
}
protocol Sub: Super {}
class Parent: Super {
func doSomething() {
// do something
}
}
class Child: Sub {
func doSomething() {
// do something else
}
}
func go( closures: [() -> Super]) {
for closure in closures {
let instance = closure()
instance.doSomething()
}
}