Typealias inside Protocol - ios

I have a typealias inside my protocol. Do I have to add the typealias to the conforming type or is there an alternative? My goal is to declare the typealias once.
protocol SomeProtocol {
associatedtype T
typealias Closure = (T) -> Void
var blocks: [Closure] { get set }
}
struct SomeStruct<T>: SomeProtocol {
typealias Closure = (T) -> Void // <- do I have to add this?
var blocks: [Closure]
}
FYI this works. Im just looking for a simpler implementation of the typealias.

You don't necessarily need the typealias in the struct -- it can be inferred:
protocol SomeProtocol {
associatedtype T
typealias Closure = (T) -> Void
var blocks: [Closure] { get set }
}
struct SomeStruct<T>: SomeProtocol {
var blocks: [(T) -> Void]
}
let someStruct = SomeStruct<Int>(blocks: [{someInt in print(someInt)}])
someStruct.blocks[0](123)

Related

How to solve Protocol 'Result' as a type cannot conform to the protocol itself error in swift 5.6

How can I work with methods that have parameters of a protocol type without knowing the specific type of the protocol?
For instance the following example would produce a "Protocol 'Result' as a type cannot conform to the protocol itself" error, because swift does not allow to call the method with an object of the Result protocol
Example:
protocol Result {
var foo: String { get }
}
struct ResultImpl: Result {
var foo = "foo"
}
struct ResultImpl2: Result {
var foo = "foo2"
}
protocol Calculator {
func processResult<T: Result>(_ result: T)
}
struct CalculatorImpl: Calculator {
func processResult<T: Result>(_ result: T) {
let _ = result.foo
}
}
func test(){
let result: Result = getResult() // get anything that implements Result interface
let calc = CalculatorImpl();
let _ = calc.processResult(result) // Protocol 'Result' as a type cannot conform to the protocol itself
}
func getResult() -> Result {
return Int.random(in: 0...1) == 0 ? ResultImpl(): ResultImpl2();
}
The function processResult shouldn't be generic, a generic will require a concrete type that conforms to Result at compile time.
func processResult(_ result: Result)

Static member cannot be used on protocol meta type

What I am trying to accomplish is to make Proxy protocol that will route my class to appropriate service.
I have 3 types of service per 1 proxy:OnlineService,OfflineService,DemoService each for one of modes (online, offline,demo).
I created protocol :
protocol Proxy {
associatedtype ServiceProtocol
associatedtype OfflineServiceType: OfflineService
associatedtype OnlineServiceType: WebService
associatedtype DemoServiceType: DemoService
}
extension Proxy {
static var service: ServiceProtocol.Type {
if isOnlineMode() {
return OfflineServiceType.self as! ServiceProtocol.Type
} else if isDemoMode(){
return DemoServiceType.self as! ServiceProtocol.Type
}else{
return OnlineServiceType.self as! ServiceProtocol.Type
}
}
}
and then on Customer proxy class
class CustomersServiceProxy: Proxy, CustomersService {
typealias ServiceProtocol = CustomersService
typealias OfflineServiceType = CustomersOfflineService
typealias OnlineServiceType = CustomerWebService
public static func customerDetails(for customer: Customer, completion: #escaping (CustomerDetails) -> Void) {
service.customerDetails(for: customer, completion: completion)
}
}
But I got error:
Static member 'customerDetails' cannot be used on protocol metataype 'CustomerServiceProxy.ServiceProtocol.Protocol' (aka 'CustomerService.Protocol').
I suggest that this happens because Proxy service variable is returning CustomerService.Type instead of Type that is conforming to CustomerService. Is there any workaround to this?
well, u r missing a step, for example:
protocol Proxcy {}
extention Proxcy {
static func a() { print("A")
}
struct A: Proxcy {}
struct B: Proxcy {
A.a()
}

Swift switch between generics type and protocol conformance

I want to reach this goal:
func parse<T>(element: Any?) -> [T] {
// if T is kind of MyProtocol, return get result
// else
let array = [T]()
//do some stuff
return array
}
func get<T: MyProtocol>(obj: Any?) -> [T] {
return //some other stuffs
}
Is it possible in Swift language?
EDIT:
I have a class, let's say Parser, with some properties. I want a unique function signature, but the executed code must vary in base of property type.
class Parser: ParserProtocol {
let property1 : [MyClass1] = parse(element: elem1)
let property2 : [MyClass2] = parse(element: elem2)
}
protocol ParserProtocol {
func parse<T>(element: Any?) -> [T]
}
is this something you could use?
protocol GenericsTypeProtocol {
func callParseLogic() -> Void
}
protocol MyProtocol : GenericsTypeProtocol {}
extension GenericsTypeProtocol {
func callParseLogic() -> Void {
print("Generic logic called")
}
}
extension GenericsTypeProtocol where Self : MyProtocol {
func callParseLogic() -> Void {
print("MyProtocol logic called")
}
}
class GenericClass : GenericsTypeProtocol { }
class MyClass : MyProtocol { }
class MixedClass : GenericsTypeProtocol, MyProtocol {}
let a = GenericClass()
a.callParseLogic() //prints: Generic logic called
let b = MyClass()
b.callParseLogic() //prints: MyProtocol logic called
let c = MixedClass()
c.callParseLogic() //prints: MyProtocol logic called

can swift functions and closures conform to Hashable?

Suppose I want to have a Set of functions or closures. Here's how I would go about it:
typealias HandlerX = () -> ()
static var handlersX = Set<HandlerX>()
This produces the following compiler error:
Type 'HandlerX' (aka '() -> ()') does not conform to protocol 'Hashable'
Is this a dead end?
Yes, this is a dead end. Hashable isn't really your problem; there's no way to decide whether two closures are Equal (which is a base requirement of Hashable).
You can create a wrapper struct for closure
struct Hashed<T>: Hashable {
let value: T
let hash: Int
init(value: T, hash: Int) {
self.value = value
self.hash = hash
}
public func hash(into hasher: inout Hasher) {
hasher.combine(hash)
}
static func == (lhs: Hashed<T>, rhs: Hashed<T>) -> Bool {
lhs.hashValue == rhs.hashValue
}
}
But you need to understand the identity of your closures. For example, it can be the class that created it, or #filename + #line, or always unique with UUID()

Extend #objc protocol with Comparable in Swift

I am trying to extend my protocol Option with Comparable to use simple .sort() method.
Below short example only with Equatable to show errors.
#objc protocol Option: Equatable {
var title: String { get }
var enabled: Bool { get }
var position: Int { get }
}
func ==(lhs: Option, rhs: Option) -> Bool {
return lhs.position == rhs.position
}
The Option protocol must be marked as #objc or inherit from NSObjectProtocol because it will be used with UIKit.
Errors:
#objc protocol 'Option' cannot refine non-#objc protocol
'Equatable'
Protocol 'Option' can only be used as a generic constraint
because it has Self or associated type requirements
Do you have any suggestion how to solve this problem?
Equatable lives in the Swift world only, thus you cannot extend it to a protocol that will be used by Objective-C. Trying to do this results in error #1
Protocols that have a Self requirement (i.e. at least one method from the protocol declaration contains Self) cannot be used as arguments to functions, or to variable declarations, only as arguments to a generic clause, e.g. func doSomething<T: Option>(argument: T).
Removing Equatable from the Option protocol declaration, and declaring == as generic on Option will solve the compile errors. As for sorting, you can also overload the < operator, and sort via that operator (without needing to implement Comparable):
#objc protocol Option {
var title: String { get }
var enabled: Bool { get }
var position: Int { get }
}
func ==<T: Option>(lhs: T, rhs: T) -> Bool {
return lhs.position == rhs.position
}
func <<T: Option>(lhs: T, rhs: T) -> Bool {
return lhs.position < rhs.position
}
This allows you to pass objects that conform to the protocol to UIKit, and to also compare them within your swift code.
class A: NSObject, Option { .. }
class B: NSObject, Option { ... }
let a = A()
let b = B()
a == b // compiles, and returns true if a and b have the same position
let c: [Option] = [a, b]
c.sort(<) // returns a sorted array by the `position` field
One important note regarding the sorting code above: if you don't specify the type for c, then the compiler infers its type as [NSObject], and the sort call will not compile due to ambiguity of the < operator. You need to explicitly declare c as [Option] to take advantage of the overloaded operator.
The issue can be fixed by the new protocol oriented programming features introduced in swift 2.0
#objc protocol 'Option' cannot refine non-#objc protocol 'Equatable'
As the error states, the Equatable protocol is a swift protocol that you can't to Obj C context
Protocol 'Option' can only be used as a generic constraint because it
has Self or associated type requirements
You can achieve this in the following way:
#objc protocol Option {
var title: String { get }
var enabled: Bool { get }
var position: Int { get }
}
extension Equatable where Self : Option
{
}
extension Comparable where Self : Option
{
}
func ==(lhs: Option, rhs: Option) -> Bool
{
return lhs.position == rhs.position
}
func <(lhs: Option, rhs: Option) -> Bool
{
return lhs.position < rhs.position
}
func >(lhs: Option, rhs: Option) -> Bool
{
return lhs.position > rhs.position
}
And your class and implementation looks like:
class MyClass: Option
{
#objc var title: String = ""
#objc var enabled: Bool = true
#objc var position: Int = 0
init()
{
}
convenience init(title : String, enabled : Bool, position: Int)
{
self.init()
self.title = title
self.enabled = enabled
self.position = position
}
}
let firstObj = MyClass()
let secondObj = MyClass()
let optionArray : [Option] = [firstObj, secondObj]
// Sort array of options
optionArray.sort(<)

Resources