Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How passing a protocol as parameter in Swift

In Objective-C, I know how passing a protocol as parameter:

- (void)MyMethod:(Protocol *)myparameter

But in Swift there is no more Protocol type.

How can I pass a protocol as parameter without knowing which is ?

like image 586
Jean Lebrument Avatar asked Jun 04 '14 15:06

Jean Lebrument


People also ask

How do I add a protocol in Swift?

To create a protocol, use the protocol keyword followed by the name you want and defined by the curly braces. Protocols can be of 2 types: read-only/read-write. Read-only means you can only get the variable, but you cannot set it. Read-write means you can both set and get properties.

Can we inherit protocol in Swift?

In Swift, protocols can inherit from one or more additional protocols.

CAN protocols have properties in Swift?

A protocol can have properties as well as methods that a class, enum or struct conforming to this protocol can implement. A protocol declaration only specifies the required property name and type.

How do protocols work in Swift?

A protocol defines a blueprint of methods, properties, and other requirements that suit a particular task or piece of functionality. The protocol can then be adopted by a class, structure, or enumeration to provide an actual implementation of those requirements.


Video Answer


2 Answers

In one of your comments you say:

"I want create a method which return an array of type of class which implements a desired protocol."

Have you tried something like the following:

//notice the use of @objc here
@objc protocol AlertProtocol
{
    func getMyName()->String
}

class Class1 : AlertProtocol
{
     let name = "Object 1"
     func getMyName() -> String
    {
        return name
    }
}

class Class2 : AlertProtocol
{
    let name = "Object 2"
    func getMyName() -> String
    {
        return name
    }
}

//borrowing from and refactoring siLo's answer
func classesConformingToProtocol(proto:Protocol) -> [AnyClass]
{
    let availableClasses : [AnyClass] = [ Class1.self, Class2.self ]

    var conformingClasses = Array<AnyClass>()

    for myClass : AnyClass in availableClasses
    {
        if myClass.conforms(to: proto)
        {
            conformingClasses.append(myClass)
        }
    }

    return conformingClasses
}

Then use the above structure like this:

let classes = classesConformingToProtocol(AlertProtocol.self)

The tricky part that does the work is the "@objc" that exposes the protocol to the objective c runtime and allows us to pass any "Protocol Type" as a parameter.

Probably at some point in the future we will be able to do this in a "pure" Swift way.

like image 123
joakim Avatar answered Oct 18 '22 14:10

joakim


Here is what I have tried:

@objc protocol Walker
{
    func walk()
}

@objc protocol Runner
{
    func run()
}

@objc class Zombie : Walker
{
    func walk () { println("Brains...") }
}

@objc class Survivor : Runner
{
    func run() { println("Aaaah, zombies!") }
}

func classesConformingToProtocol(proto:Protocol) -> AnyClass[]
{
    let availableClasses : AnyClass[] = [ Zombie.self, Survivor.self ]

    var conformingClasses = Array<AnyClass>()

    for myClass : AnyClass in availableClasses
    {
        if myClass.conformsToProtocol(proto)
        {
            conformingClasses.append(myClass)
        }
    }

    return conformingClasses
}

// This does not work
let walkers = classesConformingToProtocol(Walker.self)
let runners = classesConformingToProtocol(Runner.self)

I have been unable to convert Swift's Metatype information into a Protocol object.

like image 31
Erik Avatar answered Oct 18 '22 15:10

Erik