How to use a protocol function as block definition? - swift

Here a function b calls a and passes a completion block:
func a(completion: (_ succeeded: Bool)) {
completion(true)
}
func b() {
a() { succeeded in
...
}
}
Can I use a protocol function definition to define the block?
Something like this (which does not work):
protocol P {
func c(succeeded: Bool)
}
func a(completion: P) {
completion.c(succeeded: true)
}
func b() {
a() { c(succeeded) in
...
}
}
Note: I am not looking for the protocol/delegate concept.

The issue with using a protocol here is that functions cannot conform to a protocol, only classes, enums and structs can conform to a protocol. So you either need one of these types or an instance of one of these types, but then the instance seems superfluous. If you really want to do it the protocol way here is an example with static conformance on an enum:
import UIKit
protocol Callable {
static func call(someString: String, someInt: Int)
}
enum MyCallable: Callable {
static func call(someString: String, someInt: Int) {
print(someString, someInt)
}
}
func someFunction<T: Callable>(callable: T.Type) {
callable.call(someString: "a",someInt: 1)
}
someFunction(callable: MyCallable.self)

You can use a labeled tuple to give yourself argument labels if that is what you are after. Here is a playground example:
import UIKit
typealias MyArguements = (someInt: Int, someString: String)
func someFunction( completion: #escaping (MyArguements) -> Void) {
completion((someInt: 1, someString: "a"))
}
someFunction { tuple in
let (someInt, someString) = tuple
print(someInt, someString)
}

Related

Create an array of protocols with constrained associated types

This is a basic example of creating an array of protocols with associated types using type erasure:
protocol ProtocolA {
associatedtype T
func doSomething() -> T
}
struct AnyProtocolA<T>: ProtocolA {
private let _doSomething: (() -> T)
init<U: ProtocolA>(someProtocolA: U) where U.T == T {
_doSomething = someProtocolA.doSomething
}
func doSomething() -> T {
return _doSomething()
}
}
Creating an array of them isn't hard:
let x: [AnyProtocolA<Any>] = []
Is there any way way I can create an array of protocols which have associated types that are constrained? This is what I have tried:
protocol Validateable {
// I removed the functions and properties here to omit unreleveant code.
}
protocol ProtocolA {
associatedtype T: Validateable
func doSomething() -> T
}
struct AnyProtocolA<T: Validateable>: ProtocolA {
private let _doSomething: (() -> T)
init<U: ProtocolA>(someProtocolA: U) where U.T == T {
_doSomething = someProtocolA.doSomething
}
func doSomething() -> T {
return _doSomething()
}
}
It compiles! But didn't it defeated the chance of creating an array of AnyProtocolA's now? Now I can't use type Any as a placeholder in my array.
How do I create an array of AnyProtocolA's which has a constrained associated type? Is it even possible? This won't work since Any ofcourse doesn't conform to Validateable:
let x: [AnyProtocolA<Any>] = []
Extending Any can't be done:
extension Any: Validateable {} // Non nominal type error
Edit:
I think I already found it, just type erasure the protocol Validateable as well:
protocol Validateable {
// I removed the functions and properties here to omit unreleveant code.
}
protocol ProtocolA {
associatedtype T: Validateable
func doSomething() -> T
}
struct AnyProtocolA<T: Validateable>: ProtocolA {
private let _doSomething: (() -> T)
init<U: ProtocolA>(someProtocolA: U) where U.T == T {
_doSomething = someProtocolA.doSomething
}
func doSomething() -> T {
return _doSomething()
}
}
struct AnyValidateable<T>: Validateable {}
Now I can use it as:
let x: [AnyProtocolA<AnyValidateable<Any>>] = []
Any answers that are better are always welcome :)

Swift generic without force unwrap downcast

I try to create some generic based code:
protocol ViewModelsCreator {
associatedtype T: EditItemViewModelType
func editItemViewModel<T>() -> T
}
class PlacesListViewModel: ViewModelsCreator {
typealias T = EditPlaceViewModel
func editItemViewModel<T>() -> T {
return EditPlaceViewModel()
}
}
class EditPlaceViewModel: EditItemViewModelType {}
protocol EditItemViewModelType {}
The playground shows error:
cannot convert return expression of type 'EditPlaceViewModel' to
return type 'T'
and suggest to use
return EditPlaceViewModel() as! T
Is there any solution to avoid this (as! T) force unwrap code? I think compiler should figure out that EditPlaceViewModel is EditItemViewModelType and should satisfy this generic.
You need to remove the <T> in the ViewModelsCreator protocol and the PlacesListViewModel class.
protocol ViewModelsCreator {
associatedtype T: EditItemViewModelType
func editItemViewModel() -> T
}
class PlacesListViewModel: ViewModelsCreator {
typealias T = EditPlaceViewModel
func editItemViewModel() -> T {
return EditPlaceViewModel()
}
}
You can also remove the typealias and replace -> T with -> EditPlaceViewModel in the PlacesListViewModel class. It works either way but this is more explicit.
class PlacesListViewModel: ViewModelsCreator {
func editItemViewModel() -> EditPlaceViewModel {
return EditPlaceViewModel()
}
}

How to pass closure with argument as argument and execute it?

Initializer of class A takes an optional closure as argument:
class A {
var closure: ()?
init(closure: closure()?) {
self.closure = closure
self.closure()
}
}
I want to pass a function with an argument as the closure:
class B {
let a = A(closure: action(1)) // This throws the error: Cannot convert value of type '()' to expected argument type '(() -> Void)?'
func action(_ i: Int) {
//...
}
}
Class A should execute the closure action with argument i.
I am not sure about how to write this correctly, see error in code comment above. What has to be changed?
Please make your "what-you-have-now" code error free.
Assuming your class A like this:
class A {
typealias ClosureType = ()->Void
var closure: ClosureType?
init(closure: ClosureType?) {
self.closure = closure
//`closure` would be used later.
}
//To use the closure in class A
func someMethod() {
//call the closure
self.closure?()
}
}
With A given above, you need to rewrite your class B as:
class B {
private(set) var a: A!
init() {
//initialize all instance properties till here
a = A(closure: {[weak self] in self?.action(1)})
}
func action(i: Int) {
//...
}
}
The problem is that closure()? is not a type. And ()? is a type, but it is probably not the type you want.
If you want var closure to have as its value a certain kind of function, you need to use the type of that function in the declaration, e.g.
var closure: (Int) -> Void
Similarly, if you want init(closure:) to take as its parameter a certain kind of function, you need to use the type of that function in the declaration, e.g.
init(closure: (Int) -> Void) {
Types as Parameters
In Swift, every object has a type. For example, Int, String, etc. are likely all types you are extremely familiar with.
So when you declare a function, the explicit type (or sometimes protocols) of any parameters should be specified.
func swallowInt(number: Int) {}
Compound Types
Swift also has a concept of compound types. One example of this is Tuples. A Tuple is just a collection of other types.
let httpStatusCode: (Int, String) = (404, "Not Found")
A function could easily take a tuple as its argument:
func swallowStatusCode(statusCode: (Int, String)) {}
Another compound type is the function type. A function type consists of a tuple of parameters and a return type. So the swallowInt function from above would have the following function type: (Int) -> Void. Similarly, a function taking in an Int and a String and returning a Bool would have the following type: (Int, String) -> Bool.
Function Types As Parameters
So we can use these concepts to re-write function A:
class A {
var closure: (() -> Void)?
init(closure: (() -> Void)?) {
self.closure = closure
self.closure()
}
}
Passing an argument would then just be:
func foo(closure: (Int) -> Void) {
// Execute the closure
closure(1)
}
One way to do what I think you're attempting is with the following code:
class ViewController: UIViewController {
override func viewDidLoad() {
let _ = A.init(){Void in self.action(2)}
}
func action(i: Int) {
print(i)
}
}
class A: NSObject {
var closure : ()?
init(closure: (()->Void)? = nil) {
// Notice how this is executed before the closure
print("1")
// Make sure closure isn't nil
self.closure = closure?()
}
}

Using array of protocol in Swift class' generics

Is there any way to use array of protocol's generic?
For example,
/* I want to use protocol like below,
* but I can't because protocol is not concrete
* so cannot make array of it */
class MyClass<T where T:MyProtocol, T:[MyProtocol]> {
let result: T
}
protocol MyProtocol {
init(with: String)
}
class SpecialThing: MyProtocol {
let appleWatch: AppleWatch
init(with: String) {
self.appleWatch = AppleWatch(with)
}
}
class SampleClass {
func test {
typealias listCallback = (MyClass<[SpecialThing]>, NSError) -> ()
typealias oneCallback = (MyClass<SpecialThing>, NSError) -> ()
}
}
There can be one object or array of protocol's subclass.
I think "typealias" does not help me.
I want to find something more simple way.....
My first issue with this is that the type signature is wrong:
class MyClass<T where T:MyProtocol, T:[MyProtocol]>
That's the same type of thing as doing:
let t: String
let t: [String]
t = String("foo")
The compiler will complain because you are redefining T, once as a MyProtocol and again as an array of MyProtocol. You can't have both, you can only have one.
Answer: Use a construct like Either:
enum Either<T, U>
{
case Left(T)
case Right(U)
var leftValue: T?
{
if case .Left(let leftValue) = self
{
return leftValue
}
return nil
}
var rightValue: U?
{
if case .Right(let rightValue) = self
{
return rightValue
}
return nil
}
}
Allowing for:
class MyClass<T: MyProtocol>
{
let result: Either<T, [MyProtocol]>
}

Swift protocol extension implementing another protocol with shared associated type

Consider the following:
protocol Foo {
typealias A
func hello() -> A
}
protocol FooBar: Foo {
func hi() -> A
}
extension FooBar {
func hello() -> A {
return hi()
}
}
class FooBarClass: FooBar {
typealias A = String
func hi() -> String {
return "hello world"
}
}
This code compiles. But if I comment out explicit definition of associated type typealias A = String, then for some reason, swiftc fails to infer the type.
I'm sensing this has to do with two protocols sharing the same associated type but without a direct assertion through, for example, type parameterization (maybe associated type is not powerful/mature enough?), which makes it ambiguous for type inference.
I'm not sure if this is a bug / immaturity of the language, or maybe, I'm missing some nuances in protocol extension which rightfully lead to this behaviour.
Can someone shed some light on this?
look at this example
protocol Foo {
typealias A
func hello() -> A
}
protocol FooBar: Foo {
typealias B
func hi() -> B
}
extension FooBar {
func hello() -> B {
return hi()
}
}
class FooBarClass: FooBar {
//typealias A = String
func hi() -> String {
return "hello world"
}
}
with generics
class FooBarClass<T>: FooBar {
var t: T?
func hi() -> T? {
return t
}
}
let fbc: FooBarClass<Int> = FooBarClass()
fbc.t = 10
fbc.hello() // 10
fbc.hi() // 10
Providing explicit values for associated types in a protocol is required for conformance to said protocol. This can be accomplished by hard coding a type, as you've done with typealias A = String, or using a parameterized type as you mentioned, such as below:
class FooBarClass<T>: FooBar {
typealias A = T
...
}
Swift will not infer your associated type from an implemented method of the protocol, as there could be ambiguity with multiple methods with mismatching types. This is why the typealias must be explicitly resolved in your implementing class.