Swift best practice for multiply inheriting inits and deinits? - swift

I have two classes that ideally would have code in their inits and deinits, e.g.:
class Tappable {
init() { Registry.register(tappable: self) }
deinit { Registry.deregister(tappable: self) }
}
class Resizable {
init() { Registry.register(resizable: self) }
deinit { Registry.deregister(resizable: self) }
}
Ideally I would inherit from both, e.g.:
class UIElement: Tappable, Resizable {}
But of course I can't in Swift. My current solution is to make one a protocol and put a note in to remind me to write init and deinit with calls to the Registry, e.g.:
//: Classes that implememt `Resizable` must call `Registry.register(resizable: self)` in all `init`s and have `deinit { Registry.deregister(resizable: self) }`.
protocol Resizable {}
class UIElement: Tappable, Resizable {
override init() {
super.init()
Registry.register(resizable: self)
}
deinit { Registry.deregister(resizable: self) }
}
Is there a better way?

You could create a composite class and store your Registry classes as variables, it could look something like this:
protocol Register {
init(_ target: UIElement)
func deregister(target: UIElement)
}
class Tappable: Register {
required init(_ target: UIElement) { Registry.register(tappable: target) }
func deregister(target: UIElement) { Registry.deregister(tappable: target) }
}
class Resizable: Register {
required init(_ target: UIElement) { Registry.register(resizable: target) }
func deregister(target: UIElement) { Registry.deregister(resizable: target) }
}
class UIElement {
var traits: [Register]!
override init() {
self.traits = [Tappable(self), Resizable(self)]
}
deinit {
self.traits.forEach { $0.deregister(self) }
}
}
This way, when deinit is called on the UIElement object, all of the traits of UIElement will be deregistered.
You can test this out in a Swift Playground by adding the following at the bottom. This will create the UIElement class, have it register for the traits, and then deallocate it and have it deregister!
var test: UIElement! = UIElement()
test = nil

You could have each protocol define a required initializer:
protocol Tappable {
init(r:Registry)
}
Then any class that inherits the protocol will have to implement that initializer, which you'd hope would remind you what needed to happen there.
That doesn't work particularly-well for UIView subclasses, which need to implement UIView's designated initializers, also.

Here's another solution, which replaces your two superclasses with a single superclass, and an OptionSet. Obviously, this gets a bit unwieldy if you need to do a lot of case-specific initialization and de-initialization, but it works okay for the example given.
class Registry {
class func register(resizeable: Any) {
}
class func register(tappable: Any) {
}
}
struct ViewTraits: OptionSet {
let rawValue: Int
init(rawValue: Int) { self.rawValue = rawValue }
static let Tappable = ViewTraits(rawValue: 1)
static let Resizeable = ViewTraits(rawValue: 2)
}
protocol Traits {
var traits:ViewTraits { get }
}
class TraitedView: NSView, Traits {
var traits:ViewTraits {
get {
fatalError("Must implement a getter for Traits")
}
}
private func register() {
if (traits.contains(.Tappable)) {
Registry.register(tappable: self)
}
if (traits.contains(.Resizeable)) {
Registry.register(resizeable: self)
}
}
override init(frame:NSRect) {
super.init(frame: frame)
register()
}
required init?(coder: NSCoder) {
super.init(coder: coder)
register()
}
}
class MyView: TraitedView {
override var traits: ViewTraits {
get {
return [ViewTraits.Resizeable, ViewTraits.Tappable]
}
}
}

I have pinched everyones ideas in the playground below. Thanks.
var sequence = ""
enum Registry {
static func register(tappable _: Tappable) { sequence += "reg. tap.\n" }
static func deregister(tappable _: Tappable) { sequence += "dereg. tap.\n" }
static func register(resizable _: Resizable) { sequence += "reg. res.\n" }
static func deregister(resizable _: Resizable) { sequence += "dereg. res.\n" }
}
class Registrar {
init() {
if let tappable = self as? Tappable {
Registry.register(tappable: tappable)
}
if let resizable = self as? Resizable {
Registry.register(resizable: resizable)
}
}
deinit {
if let tappable = self as? Tappable {
Registry.deregister(tappable: tappable)
}
if let resizable = self as? Resizable {
Registry.deregister(resizable: resizable)
}
}
}
protocol Tappable {
func tap()
}
extension Tappable {
func tap() { sequence += "tap\n" }
}
protocol Resizable {
func resize()
}
extension Resizable {
func resize() { sequence += "resize\n" }
}
class UIElement: Registrar, Tappable, Resizable {
}
var uie: UIElement! = UIElement()
uie.tap()
uie.resize()
uie = nil
sequence // "reg. tap.\nreg. res.\ntap\nresize\ndereg. tap.\ndereg. res.\n"

Related

overriding declarations in extensions is not supported - swift

I made a minimal reproducible code of my issue.
enum Animal {
case cat
case dog
}
protocol AdoptPet {
func petIs(pet: Animal)
}
class Delegate {
}
extension Delegate: AdoptPet {
func petIs(pet: Animal) {
print("not implemeted")
}
}
class Girl: Delegate {
}
extension Girl {
override func petIs(pet: Animal) { // overriding declarations in extensions is not supported
print(pet)
}
}
class PetCenter {
init () {
}
func setup(adpoter: Delegate){
let pet: Animal = .cat
adpoter.petIs(pet: pet)
}
}
let petCenter = PetCenter()
let adpoter: Girl = Girl()
petCenter.setup(adpoter: adpoter)
What should I change in the code to make this compile ?
You need to move both the declaration of the function and the override into the type declarations from extensions. So Delegate needs to contain the petIs implementation in its declaration and Girl needs to override the petIs function in its body as well (using the override keyword) rather than in an extension.
class Delegate: AdoptPet {
func petIs(pet: Animal) {
print("not implemeted")
}
}
class Girl: Delegate {
override func petIs(pet: Animal) {
print(pet)
}
}
class PetCenter {
init () {
}
func setup(adopter: Delegate){
let pet: Animal = .cat
adopter.petIs(pet: pet)
}
}
let petCenter = PetCenter()
let adopter = Girl()
petCenter.setup(adopter: adopter) // cat

Swift 4.3 - protocols passing data between 2 files

I am struggling with understanding how protocols work. I have 2 files and want to use protocol to pass data... Here's what I am doing:
In ViewController.swift
protocol workingProtocol { func myFunc(strValue: String)}
class ViewController: UIViewController {
var interactor = workingProtocol
#objc func doneBtn() {
interactor.myFunc(strValue: "str")
}
}
In Interactor.swift
class Interactor {
func myFunc(strValue: String) {
print(strValue)
}
}
The data is not printing from Interactor.swift
Unfortunately I can't see how you inject interaction class, also your code has some problem with syntax. Here is how it should look:
protocol WorkingProtocol: AnyObject {
func myFunc(strValue: String)
}
final class ViewController: UIViewController {
var interactor: WorkingProtocol
#objc func doneBtn() {
interactor.myFunc(strValue: "str")
}
}
final class Interactor: WorkingProtocol {
func myFunc(strValue: String) {
print(strValue)
}
}
And how to use:
let interactor: WorkingProtocol = Interactor()
let vc = ViewController(interactor: interactor)
vc.doneBtn()
Protocols defines a blueprint of methods, properties and other requirements that suite a piece of functionality.
This is an example about how it works based on your code
protocol ProtocolName {
func functionName(strValue: String)
}
class ViewController {
var interactor: ProtocolName? = nil
#objc
fileprivate func doneBtn() {
interactor?.functionName(strValue: "Passing data to interactor using protocols")
}
}
class Interactor: ProtocolName {
func functionName(strValue: String) {
print("Showing value\n", strValue)
}
}
let interactor = Interactor()
let viewController = ViewController()
viewController.interactor = interactor
viewController.doneBtn()
Another example:
protocol ProtocolName {
func functionName(strValue: String)
}
class ViewController1 {
let interactor = Interactor1()
/// Init or viewDidLoad() if you're using ViewController classes.
init() {
interactor.delegate = self
}
}
extension ViewController1: ProtocolName {
func functionName(strValue: String) {
print("Printing the value: \(strValue)")
}
}
class Interactor1 {
var delegate: ProtocolName?
func someAction() {
delegate?.functionName(strValue: "Executed action in interactor.")
}
}
let vc = ViewController1()
vc.interactor.someAction()

Protocol associatedtype as a type for delegate

The purpose of what I am trying to do is to make it possible to put objects which implements ChildOfRootClass to one array (look at AbstractClass -> children) and put at each ChildNClass instance object a link to its parent (look weak var delegate variable). So I want make type of delegate in each ChildOfRootClass generic.
Hope code will explain what exactly I have meant.
// Parent class for RootClass and Child1Class, Child2Class etc
class AbstractClass {
init() { }
init(smth: String) { }
var children = [String : ChildOfRootClass]()
func add(key: String, child: ChildOfRootClass) {
children[key] = child
}
}
Delegate protocols for each of children.
protocol ChildDelegate: class { }
protocol Child1ClassDelegate: ChildDelegate { func rr() }
protocol Child2ClassDelegate: ChildDelegate { }
class RootClass: AbstractClass {
override init() {
super.init()
}
}
extension RootClass: Child1ClassDelegate {
func rr() { }
}
Children classes.
protocol ChildOfRootClass {
associatedtype ChildOfRootClassDelegateType: ChildDelegate
weak var delegate: ChildOfRootClassDelegateType? { set get }
init(smth: String)
}
class Child1Class: AbstractClass, ChildOfRootClass {
typealias ChildOfRootClassDelegateType = Child1Delegate
weak var delegate: Child1Delegate?
required override init(smth: String) {
super.init(smth: smth)
}
}
extension Child1Class: Child2ClassDelegate { }
class Child2Class: AbstractClass/*, ChildOfRootClass*/ {
required override init(smth: String) {
super.init(smth: smth)
}
}
How I want to use it.
let root = RootClass()
let child1 = Child1Class(smth: "1")
let child2 = Child2Class(smth: "2")
child1.add(key: "child2", child: child2)
root.add(key: "child1", child: child1)

Ambiguous functions in multiple protocol extensions?

I have multiple protocols that have the same function name. Some protocols have associated types, where I can't figure out how to call the functions as I do in non-generic protocols. I get the error: Protocol 'MyProtocol1' can only be used as a generic contraint because it has Self or associated type requirements
Here's what I'm trying to do:
protocol Serviceable {
associatedtype DataType
func get(handler: ([DataType] -> Void)?)
}
struct PostService: Serviceable {
func get(handler: ([String] -> Void)? = nil) {
print("Do something...")
}
}
protocol MyProtocol1: class {
associatedtype ServiceType: Serviceable
var service: ServiceType { get }
}
extension MyProtocol1 {
func didLoad(delegate: Self) {
print("MyProtocol1.didLoad()")
}
}
protocol MyProtocol2: class {
}
extension MyProtocol2 {
func didLoad(delegate: MyProtocol2) {
print("MyProtocol2.didLoad()")
}
}
class MyViewController: UIViewController, MyProtocol1, MyProtocol2 {
let service = PostService()
override func viewDidLoad() {
super.viewDidLoad()
didLoad(self as MyProtocol1) // Error here: Protocol 'MyProtocol1' can only be used as a generic contraint because it has Self or associated type requirements
didLoad(self as MyProtocol2)
}
}
How can I specifically call the function from a generic protocol extension?
It's simple to achieve by turning the protocol into a generic (see below), or by creating a type eraser for these protocols, but this very strongly suggests that you have a design problem and you should redesign your classes and/or extensions. A collision like this suggests strongly that MyStruct is doing too many things itself because it's being pulled in multiple directions by MyProtocol1 and MyProtocol2. There should likely be two objects here instead. (Composition rather than inheritance.)
class MyStruct: MyProtocol1, MyProtocol2 {
let service = PostService()
func prot1Load<T: MyProtocol1>(t: T) {
t.didLoad()
}
func prot2Load<T: MyProtocol2>(t: T) {
t.didLoad()
}
init() {
prot1Load(self)
prot2Load(self)
}
}
To your particular example in the comments, I would use composition rather than inheritance. You're treating protocols like multiple-inheritance, which is almost never right. Instead compose out of things that conform to a protocol.
protocol LoadProviding {
func load()
}
struct MyLoader1: LoadProviding {
func load() {
print("MyLoader1.didLoad()")
}
}
struct MyLoader2: LoadProviding {
func load() {
print("MyLoader2.didLoad()")
}
}
protocol Loader {
var loaders: [LoadProviding] { get }
}
extension Loader {
func loadAll() {
for loader in loaders {
loader.load()
}
}
}
class MyStruct: Loader {
let service = PostService()
let loaders: [LoadProviding] = [MyLoader1(), MyLoader2()]
init() {
loadAll()
}
}
Of course you don't really have to have LoadProviding be a full struct. It could just be a function if that's all you need:
typealias LoadProviding = () -> Void
func myLoader1() {
print("MyLoader1.didLoad()")
}
func myLoader2() {
print("MyLoader2.didLoad()")
}
protocol Loader {
var loaders: [LoadProviding] { get }
}
extension Loader {
func loadAll() {
for loader in loaders {
loader()
}
}
}
class MyStruct: Loader {
let service = PostService()
let loaders: [LoadProviding] = [myLoader1, myLoader2]
init() {
loadAll()
}
}
If you have time to wade through a video on the subject, you may be interested in the Beyond Crusty: Real World Protocols talk from dotSwift. It's about this and similar problems.

Observer Pattern in Swift

I want to implement an observer pattern, but I do not find the proper programming language constructs in Swift (also 2.0). The main problems are:
protocol and extension does not allow stored properties.
In classes we could add stored properties, but we can not force a subclass to override some of its inherited methods.
This is what I want:
{class|protocol|extension|whathaveyou} Sensor {
var observers = Array<Any>() // This is not possible in protocol and extensions
// The following is does not work in classes
func switchOn()
func switchOff()
var isRunning : Bool {
get
}
}
class LightSensor : Sensor {
//...
override func switchOn() {
// turn the sensor on
}
}
// In the class C, implementing the protocol 'ObserverProtocol'
var lightSensor = LightSensor()
lightSensor.switchOn()
lightSensor.registerObserver(self) // This is what I want
And here comes what is possible to my knowledge:
class Sensor {
private var observers = Array<Observer>()
func registerObserver(observer:ObserverDelegate) {
observers.append(observer)
}
}
protocol SensorProtocol {
func switchOn()
func switchOff()
var isRunning : Bool {
get
}
}
class LightSensor : Sensor, SensorProtocol {
func switchOn() {
//
}
func switchOff() {
//
}
var isRunning : Bool {
get {
return // whatever
}
}
}
But this is not very convenient, because both Sensor and SensorProtocol should come hand in hand, and are both requirements the subclass LightSensor has to fulfill.
Any ideas?
A protocol is an abstract set of requirements shared across a number of (potentially very different) other objects. As such, it's illogical to store data in a protocol. That would be like global state. I can see that you want to define the specification for how the observers are stored though. That would also allow 'you' to remove 'someone else' from being an observer, and it's very restrictive about how the observers are stored.
So, your protocol should expose methods to add and remove 'yourself' as an observer. It's then the responsibility of the object implementing the protocol to decide how and where the observers are stored and to implement the addition and removal.
You could create a struct to work with your protocols, something like:
protocol Observer: class {
func notify(target: Any)
}
protocol Observable {
mutating func addObserver(observer: Observer)
mutating func removeObserver(observer: Observer)
}
struct Observation: Observable {
var observers = [Observer]()
mutating func addObserver(observer: Observer) {
print("adding")
observers.append(observer)
}
mutating func removeObserver(observer: Observer) {
print("removing")
for i in observers.indices {
if observers[i] === observer {
observers.removeAtIndex(i)
break
}
}
}
func notify(target: Any) {
print("notifying")
for observer in observers {
observer.notify(target)
}
}
}
struct ATarget: Observable {
var observation = Observation()
mutating func addObserver(observer: Observer) {
observation.addObserver(observer)
}
mutating func removeObserver(observer: Observer) {
observation.removeObserver(observer)
}
func notifyObservers() {
observation.notify(self)
}
}
class AnObserver: Observer {
func notify(target: Any) {
print("notified!")
}
}
let myObserver = AnObserver()
var myTarget: Observable = ATarget()
myTarget.addObserver(myObserver)
if let myTarget = myTarget as? ATarget {
myTarget.notifyObservers()
}
This is my solution in Swift 3
import UIKit
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
var objectToObserve = ObjectToObserve()
let observer = Observer()
let observer1 = Observer()
objectToObserve.add(observer: observer, notifyOnRegister: true)
objectToObserve.add(observer: observer1, notifyOnRegister: true)
}
}
//
// MARK: Protocol
//
protocol Observing: class {
func doSomething()
func doSomethingClosure(completion: () -> Void)
}
protocol Observable {
}
extension Observable {
private var observers: [Observing] {
get {
return [Observing]()
}
set {
//Do nothing
}
}
mutating func add(observer: Observing, notifyOnRegister: Bool) {
if !observers.contains(where: { $0 === observer }) {
observers.append(observer)
if notifyOnRegister {
observer.doSomething()
observer.doSomethingClosure(completion: {
print("Completion")
})
}
}
}
mutating func remove(observer: Observing) {
observers = observers.filter({ $0 !== observer })
}
}
//
// MARK: Observing
//
class ObjectToObserve: Observable {
init() {
print("Init ObjectToObserve")
}
}
class Observer: Observing {
init() {
print("Init Observer")
}
func doSomething() {
print("Do something")
}
func doSomethingClosure(completion: () -> Void) {
print("Do something Closure")
completion()
}
}
All answers above incorrectly use an array for retaining the observers, which may create retain cycles because of the strong references.
Also in general you may not want to allow the same observer to register itself twice.
The presented solutions also are not general purpose or lack type safety. I reference my blog post here which presents a full solution in a Swifty manner:
https://www.behindmedia.com/2017/12/23/implementing-the-observer-pattern-in-swift/
Well, you can certainly overcome the restriction of not having stored properties on extensions.
Maybe that way you can complement one of the proposed solutions with an extension that helps you avoid creating the observer list in each subclass / protocol implementation.
Although extensions can't have stored properties, you can actually get them by using the Objective-C Runtime. Assuming you have a base class for your sensors (BaseSensor) and a protocol for observers (SensorObserver):
import Foundation
import ObjectiveC
private var MyObserverListKey: UInt8 = 0
extension BaseSensor {
var observers:[SensorObserver] {
get {
if let observers = objc_getAssociatedObject( self, &MyObserverListKey ) as? [SensorObserver] {
return observers
}
else {
var observers = [SensorObserver]()
objc_setAssociatedObject( self, &MyObserverListKey, observers, objc_AssociationPolicy(OBJC_ASSOCIATION_RETAIN_NONATOMIC) )
return observers
}
}
set(value) {
objc_setAssociatedObject( self, &MyObserverListKey, observers, objc_AssociationPolicy(OBJC_ASSOCIATION_RETAIN_NONATOMIC) )
}
}
}
To be clear, even though you would need BaseSensor and all Sensors to inherit from it in order to have this property, BaseSensor wouldn't actually implement the Sensor protocol.
It's a bit weird, but I think it would suit your needs:
class BaseSensor {
}
protocol Sensor {
func switchOn()
}
class LightSensor: BaseSensor, Sensor {
func switchOn() {
// whatever
}
}
With Swift 2.0 this would be much simpler, since you can use Protocol Extensions, so you could simply do this:
protocol Sensor {
func switchOn()
}
extension Sensor {
// Here the code from the previous implementation of the extension of BaseSensor
}
class LightSensor : Sensor {
func switchOn() {
// whatever
}
}
Way better.