Why Swift Call Too Shallow Here

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



Leave a reply



Submit