Swift override static method compile error - swift

I have these two swift classes:
class A {
static func list(completion: (_ result:[A]?) -> Void) {
completion (nil)
}
static func get(completion: (_ result:A?) -> Void) {
completion (nil)
}
}
class B: A {
static func list(completion: (_ result:[B]?) -> Void) {
completion (nil)
}
static func get(completion: (_ result:B?) -> Void) {
completion (nil)
}
}
Trying to compile this raise the error "overriding declaration requires an 'override' keyword" but just for the 'get' method of class B. 'list' method compiles fine. What is the difference between [B]? and B? for the compiler in this case?
Edit: Also notice that adding 'override' is not possible. I get the error 'Cannot override static method'.

In class B, the method list is a separate method from list in class A. They just share the same name, that's all.
The parameters of the two list methods are actually different:
// A.list
static func list(completion: (_ result:[A]?) -> Void) {
// B.list
static func list(completion: (_ result:[B]?) -> Void) {
A.list takes an argument of type (_ result: [A]?) -> Void while B.list takes a (_ result: [B]?) -> Void. The array type in the closure type's parameter list is different!
So you're not overridding anything, you're just overloading.
Note:
static methods can never be overridden! If you want to override a method, use class instead of static.
class A {
class func get(completion: (_ result:A?) -> Void) {
completion (nil)
}
}
class B: A {
override class func get(completion: (_ result:B?) -> Void) {
completion (nil)
}
}

In short, as per rule, static methods can't be overridden.

Related

Given the same callback implementation, abstract function calls

Assuming I have 2 functions foo and bar defined below.
func foo(completion: #escaping (Response) -> Void)
func bar(a: Int, completion: #escaping (Response) -> Void)
Then I have 2 different functions that use foo and bar
func doSomethingWithFoo() {
foo { response in
handleResponse(response)
}
}
func doSomethingWithBar() {
bar(a: 42) { response in
handleResponse(response)
}
}
doSomethingWithFoo and doSomethingWithBar are very similar. They do the exact same thing with response they get in the completion callback.
My question is: is there a way in Swift to generalize doSomethingWithFoo and doSomethingWithBar? Maybe something in line with the following.
func doSomething(<???>) {
<???> { response in
handleResponse(response)
}
}
<???> is a placeholder for passing either foo or bar or even any other function that also accepts a callback of type (Response) -> Void.
I'll appreciate any help/insights. Thanks.
You can declare a function like this :
func doSomething(fooBar: (_ completion: #escaping (String) -> Void) -> Void) -> Void {
fooBar(handleResponse)
}
Which you would call like this:
doSomething(fooBar: { bar(a: 42, completion: $0) })
doSomething(fooBar: foo)

Pass a closure in a function

I have a little experience in Swift and facing a problem to pass a closure in a function as a parameter.
//1.
public func changeMyStatus(to f:?, _ completion:#escaping (_ isSucced:Bool)->()){
//
}
//2.
func goLive(_ completion:#escaping (_ isSucced:Bool)->()){
}
//3.
func goNonLive(_ completion:#escaping (_ isSucced:Bool)->()){
}
Now , I want to use first function in my controller and wants to pass second/third function as a parameter. Closure in first will return true/false depending on what returned by closure in second/third.
i)What will be the type I should put in first function?
Also I want to call first function from my class like this
changeMyStatus(to: goNonLive) { (isSuccess) in
}
please help
You need to change the changeMyStatus function signature and implementation like:
public func changeMyStatus(to f: (#escaping (Bool) -> ()) -> () , _ completion:#escaping (_ isSucced:Bool)->()){
f { (status) in
completion(status)
}
}
You can call these function like:
// goLive
changeMyStatus(to: goLive(_:)) { (status) in
print(status)
}
// goNonLive
changeMyStatus(to: goNonLive(_:)) { (status) in
print(status)
}
Your second and third function has a completion parameter with a type of : (Bool -> Void) -> Void
So in order to pass it to your first function, try this way :
public func changeMyStatus(to f: ((Bool) -> ()), _ completion:#escaping (_ isSucced:Bool)->()) { // Your body}
In Swift, you need to see a function as a type like Int, Double, String...

Cannot convert value of type '(T) -> Void'

Example:
struct Wrapper<T> {
var key: Int = 0
var listeners: [Int: (T) -> Void] = Dictionary()
mutating func add(_ handler:#escaping (T) -> Void) {
self.key += 1
self.listeners[self.key] = handler
}
func get(key: Int) -> (T) -> Void {
return self.listeners[key]!
}
}
Test protocol:
protocol CommonProtocol {
}
Class that create Wrapper of test class
class C {
var wrapper: Wrapper = Wrapper<CommonProtocol>()
func add<T: CommonProtocol>(_ handler: #escaping (T) -> Void) {
self.wrapper.add(handler) //Cannot convert value of type '(T) -> Void' to expected argument type '(CommonProtocol) -> Void'
}
}
Image with error
I get error:
Cannot convert value of type '(T) -> Void' to expected argument type '(CommonProtocol) -> Void'
Question:
Why (T) -> Void can't be casted to (CommonProtocol) -> Void ? The T
is explicitly declared as <T: CommonProtocol>
This is my first question, if you have some suggestions please don't hesitate to contact me
You don't need to make func add generic.
When you specify in func add<T: CommonProtocol>... you explicitly telling the compiler that your function accepts all Types that inherit CommonProtocol but your Wrapper specifies that accepts CommonProtocol not inherited types.
Solution
Either type-erase class C:
Class C<T: CommonProtocol> {
var wrapper: Wrapper<T>
....
}
or if type T doesn't actually matter to you then:
func add(_ handler: #escaping (CommonProtocol) -> Void)
but second one doesn't make sense at all. You have to downcast it every-time you'll use this method (and downcasts are very bad :D)
Note: It's actually not related to this question, but one of your options is to type-erase the CommonProtocol too.

Swift - Overloading Static Methods

I have been trying to overload a static method for a public class in Swift 2.
How is that possible? This is similar to what I want to achieve:
static func test(message: String) -> Void)?) { ### }
static func test(message: String, number: Int) -> Void)?) { ### }
It's unclear what you're trying to do exactly, but there are two extra closing parenthesis. It looks like maybe you're trying to take a closure argument?
If the intent is to take a String argument in the first method (and a String & Int in the second) and return Void, then your syntax should look like this:
static func test(message: String) { /* implementation */ }
static func test(message: String, number: Int) { /* implementation */ }
However, if the intent is to take an optional closure which takes a String and returns nothing, then the syntax looks like this:
static func test(closure: ((String) -> Void)?) {
// implementation
}
And then if the closure also takes an Int:
static func test(closure: ((String, Int) -> Void)?) {
// implementation
}

Swift compiler is unable to resolve recursive use of generics

I am trying to implement the chain of responsibility pattern in Swift.
public class Chain<T, U> {
private var command: (T?, (U?) -> Void) -> Void
private var runCommand: (() -> Void)?
private var nextCommand: ((U?) -> Void)?
private init(command: (T?, (U?) -> Void) -> Void) {
self.command = command
}
private func next(u: U?) {
self.nextCommand?(u)
}
func then<V>(command: (U?, (V?) -> Void) -> Void) -> Chain<U, V> {
let c = Chain<U, V>(command: command)
self.nextCommand = { command($0, c.next) }
c.runCommand = self.runCommand
return c
}
func endWith(command: (U?) -> Void) {
self.nextCommand = command
self.runCommand!()
}
static func build<V>(command: ((V?) -> Void) -> Void) -> Chain<AnyObject, V> {
let c = Chain<AnyObject, V>(command: { _, next in command(next) })
c.runCommand = { command(c.next) }
return c
}
}
My class does not raise any compilation error but a simple use case (such as the one below) does not work. It raises the following error: error: cannot invoke 'endWith' with an argument list of type '((_?) -> ()) ; expected an argument list of type '((U?) -> Void)'
Any thought?
Chain.build { next in
print("Foo")
next("Bar")
}
.then { o, next in
print(o)
next(15)
}
.endWith { o in
print(o)
}
I know it is an edge case of generics usage in Swift. However, as it is not possible to explicitly specialize a generic type, I have not found any solution so far.
The compiler isn't able to infer the types in your example. You just need to specify them where they're ambiguous:
Chain<String,Int>.build { next in
print("Foo")
next("Bar")
}
.then { (o: String?, next: Int? -> Void) in
print(o)
next(15)
}
.endWith { o in
print(o)
}