How to properly implement the Equatable protocol in a class hierarchy?
After lots of research and some trial and error I finally came up with a working solution. The first step was moving the ==
operator from inside the class to the global scope. This fixed the errors about static
and final
.
For the base class this became:
func == (lhs: Base, rhs: Base) -> Bool {
return lhs.x == rhs.x
}
class Base : Equatable {
var x : Int
}
And for the subclass:
func == (lhs: Subclass, rhs: Subclass) -> Bool {
return true
}
class Subclass : Base {
var y : String
}
Now the only part left is figuring out how to call the ==
operator of the base class from the ==
operator of the subclass. This led me to the final solution:
func == (lhs: Subclass, rhs: Subclass) -> Bool {
if lhs.y == rhs.y {
if lhs as Base == rhs as Base {
return true
}
}
return false
}
That first if
statement results in a call to the ==
operator in the base class.
The final solution:
Base.swift:
func == (lhs: Base, rhs: Base) -> Bool {
return lhs.x == rhs.x
}
class Base : Equatable {
var x : Int
}
Subclass.swift:
func == (lhs: Subclass, rhs: Subclass) -> Bool {
if lhs.y == rhs.y {
if lhs as Base == rhs as Base {
return true
}
}
return false
}
class Subclass : Base {
var y : String
}
Upcast non-generic ObjC Classes to parent class for Swift method parameter
You're parameterizing on Parent
rather than Type
, which the thing you're actually changing. You mean:
func callFunc<T>(parent: Parent<T>) { ... }
While you could explicitly call out T: Type
, this isn't really necessary, since Parent already enforces that.
Swift too fast read and create the array before API finish write to array
You can change the implementation of "fetchingSunServer" method a bit like this:
func fetchingSunServer(completion: @escaping (() -> Void)) {
//// Your code for fetching the data and after getting the data from server
completion()
}
your implementation will be like :
self.fetchingSunServer {
DispatchQueue.main.async {
print("\(sunrisesunsetString.count)\n\(sunrisesunset1970.count)\nFinished create data.")
}
}
you don't have to use DispatchGroup
in this scenario then.
At runtime, how does Swift know which implementation to use?
The Swift runtime uses a Protocol Witness Table which holds pointers to each type's implementations of the protocol methods.
Mike Ash explains it best in his article Exploring Swift Memory Layout, Part II:
The last one, at offset 32 is a "protocol witness table" for the underlying type and the protocol, which contains pointers to the type's implementations of the protocol methods. This is how the compiler is able to invoke methods, such as p(), on a value of protocol type without knowing the underlying type at runtime.
I would also watch the WWDC video Understanding Swift Performance as suggested in the comments by Hamish.
If you type too fast in search-bar API call errors out
As other guys mentioned, I think it's a bad practice to query the api on every stroke, use a Debouncer Use it as blue print adjust for your own needs.
Btw like libs like reactiveKit have Debouncer build in. easy to use.
class Debouncer {
var handler: (() -> Void)? {
didSet {
worker?.cancel()
if let handler = handler {
let worker = DispatchWorkItem(block: handler)
queue.asyncAfter(deadline: .now() + timeInterval, execute: worker)
self.worker = worker
}
}
}
private let timeInterval: TimeInterval
private var worker: DispatchWorkItem?
private let queue: DispatchQueue
init(timeInterval: TimeInterval, queue: DispatchQueue = .main) {
self.timeInterval = timeInterval
self.queue = queue
}
func cancel() {
worker?.cancel()
worker = nil
}
}
class Throttler {
var handler: (() -> Void)? {
didSet {
if worker == nil {
let worker = DispatchWorkItem { [weak self] in
self?.handler?()
self?.worker = nil
}
self.worker = worker
queue.asyncAfter(deadline: .now() + timeInterval, execute: worker)
}
}
}
private let timeInterval: TimeInterval
private var worker: DispatchWorkItem?
private let queue: DispatchQueue
init(timeInterval: TimeInterval, queue: DispatchQueue = .main) {
self.timeInterval = timeInterval
self.queue = queue
}
func cancel() {
worker?.cancel()
worker = nil
}
}
Related Topics
Custom Radix Columns (+Special Characters)
How to Override Setter in Swift
How to Print Http Request to Console
"'Init' Is Deprecated" Warning After Swift4 Convert
Error "[Sharesheet] Connection Invalidated" Error iOS13+ But Not on iOS 11.4
Set Multiple Arrow Directions on UIpopovercontroller in Swift
Can't Get Throws to Work with Function with Completion Handler
How to Update UIviewrepresentable with Observableobject
What Was The Reason for Swift Assignment Evaluation to Void
When How to Start Submitting Apps to The iOS App Store Written Using The Swift Programming Language
Check Os Version Using Swift on MAC Os X
Loading Image from Assets to Nsimage Keep Getting Error, Expecting Nsimage.Name
More Precision Than Double in Swift
Why Does Compactmap Return a Nil Result
How to Invoke Method with Cvalistpointer Parameters in Swift