Swift Protocols Cheatsheet

Swift protocols define an interface or type that other structures can conform to. This includes structures such as: classes, structs, enums, and other protocols. Just like enums classes in Swift protocols are more advanced than their counterparts in Objective-C. Here is everything you need to know about protocols in Swift. (Note: Swift 1.2 Xcode 6.3)

Protocol Basics

Protocol Definition:

Here is the simplest protocol you can define in Swift:

protocol AnInterface {

}

A class or a struct can conform to or adopt a protocol like this:

class User: Person, AnInterface {

}

struct SomeDataStructure: AnInterface {

}

enum SomeEnum: AnInterface {

}

Note that you define a class by giving it a super class type after the colon and then list all the protocols it conforms to. If you want to inherit your class from a base class (and its protocols), you must type the base class first and then type all the protocols.

When using struct or enum you don't need a super class, you just start listing protocols instead.

Properties:

To define a property requirement you add a property just like any other var in Swift type but you need to specify whether the property is going to be gettable or gettable and settable.

protocol SomeProtocol {  
    var firstName: String { get }    
    var lastName: String { get set }    
}

class Person: SomeProtocol {  
    var firstName: String
    var lastName: String
}

In the case of static class properties you do the same but prepend your property definition with the static keyword.

protocol SomeProtocol {  
    static var firstName: String { get }    
    static var lastName: String { get set }    
}

class Person: SomeProtocol {  
    static var firstName: String 
    static var lastName: String
}

Methods:

Similarly, you can define protocol methods:

protocol SomeProtocol {  
    func method1()
    static func method2()
}

class Person: SomeProtocol {  
    func method1() {
        // method implementation
    }

    static func method2() {
        // method implementation
    }
}

Notice how the same rule of a static prefix applies for class or type level methods. Protocols use the same syntax as normal methods, but are not allowed to specify default values for method parameters.

Optionals:

By default all the properties and methods declared in your protocol will be required by the conforming type. You can have optional methods and properties (just like in Objective-C protocols). The trick is that a protocol with optionals has to be Objective-C compatible and can be adopted only by class types (no enum or struct).

@objc protocol SomeProtocol {
    var name: String { get }
    optional static func test()
}

@objc class Person: SomeProtocol {
    var name: String

    init() {
        name = "Name"
    }

    static func test() {

    }
}

Mutation:

Structures and enumerations are value types. By default, the properties of a value type cannot be modified from within its instance methods.

Apple Doc

Swift protocols can define methods that mutate underlying value type (enum or struct) using keyword mutating. (See the Apple Doc Modifying Value Types from Within Instance Methods)

The idea is that if a method has the mutating keyword prepended then a value type that adopts that protocol is allowed to mutate (change) its underlying values.

protocol Changeable {  
    mutating func changeMethod()
}

struct DataStructureOfSomeKind: Changeable {  
    var someName: String

    mutating func changeMethod() {
        someName = "some other value"
    }
}

var structInstance: DataStructureOfSomeKind = DataStructureOfSomeKind(someName: "some string value")

print(structInstance.someName)

structInstance.changeMethod()

print(structInstance.someName)  

Extensions:

Another way to have a type conform to a protocol is through extensions. The syntax is similar to the basic protocol conformance shown above but you need to use the extension keyword and provide the implementation.

protocol AnInterface {  
    func method()
}

class User: Person {

}

extension User: AnInterface {  
    func method() {

    }
}

Protocol Conformance

You can check to see if a type conforms to a protocol or you can cast it to one using is and as operators as described in Swift Type Casting. But you can only check for protocol conformance if you use the @objc attribute, just like with optionals.

@objc protocol SomeProtocol {
    var name: String { get }
}

@objc class Person: SomeProtocol {
    var name: String

    init() {
        name = "Name"
    }
}

let person: AnyObject = Person()

if person is SomeProtocol {  
    print("person: \(person.name)");
} else {
    print("nope")
}

let people: [AnyObject] = [  
    Person(),
    NSObject(),
    Person()
]

for object in people {  
    if let person = object as? SomeProtocol {
        print("\(person.name)")
    } else {
        print("this is something else")
    }
}

Inheritance

Protocols can inherit from one or many protocols. When you adopt a protocol that has inherited from other protocols you need it to conform not only to that protocol’s requirements but also to the requirements imposed by that protocol’s super protocols. In the example below the Car class conforms to SomeProtocol3 which effectively makes it conform to SomeProtocol1 and SomeProtocol2 because SomeProtocol3 inherits from them.

protocol SomeProtocol1 {  
    func method1()
    func method2()
}

protocol SomeProtocol2 {  
    func method3()
    func method4()
}

protocol SomeProtocol3: SomeProtocol1, SomeProtocol2 {  
    func method5()
    func method6()
}

class Car: SomeProtocol3 {

    func method5() {

    }

    func method6() {

    }

    func method3() {

    }

    func method4() {

    }

    func method2() {

    }

    func method1() {

    }
}

Composition

In Swift when you define a method it is possible to require a method parameter that conforms to multiple protocols at the same time. Let's expand on the example above:

func someMethod(firstMethodParam: String, secondMethodParam: protocol<SomeProtocol1, SomeProtocol2>) {  
    secondMethodParam.method1()
    secondMethodParam.method2()
    secondMethodParam.method3()
    secondMethodParam.method4()
}

let car = Car()

someMethod("a string", car)  

Here we define a function someMethod that takes two params and the second param is of a protocol composition type protocol<SomeProtocol1, SomeProtocol2>. That means that any object that conforms to SomeProtocol1 and SomeProtocol2 at the same time, through direct conformance or through inheritance, will satisfy the composition requirement. That is why the car object can be passed to that function. If the Car class implements SomeProtocol1 and SomeProtocol2 directly like this: class Car: SomeProtocol1, SomeProtocol1 it will satisfy the requirements as well.

Note:

Protocol compositions do not define a new, permanent, protocol type. Rather, they define a temporary local protocol that has the combined requirements of all protocols in the composition.

(reference Apple Doc)

How to make it work with Objective-C

In order to make Swift protocols work with Objective-C you need to prefix them with the @objc attribute. That will make your protocol work with Objective-C but you'll only be able to use it with class type, enum or struct are excluded.

protocol SomeProtocol {  
    func someMethod()
}
@interface Car : NSObject<SomeProtocol>

@end

@implementation Car
- (void)someMethod {

}
@end

Conclusion

For the most part, Swift protocols (except optionals) work the same way as Objective-C protocols. They have many additional features that make them even more useful.

If you have any questions about protocols or Swift in general feel free to leave a comment below or shoot us an email at info@smartcloud.io. We'd be happy to help you.

__
Alex Bush @alexvbush.
Editor: Tim Baron.

comments powered by Disqus