Swift: The rules of being optional (Xcode 6 GM)

In a regular Swift protocol every method and property that is declared must be used by any class, struct or enum that adopts the protocol. But this isn't the way it has always been. In Objective-C protocols have optional methods and properties alongside the methods and properties that must be implemented. With Swift these optional methods and properties haven't disappeared, but there are some special requirements in order to get them working.

Exposing your protocol to the Objective-C

The first step is to prefix your protocol with the @objc attribute. In brief,
The @objc attribute makes your Swift API available in Objective-C and the Objective-C runtime. (Apple)
and I'll provide more details on this in a later post. The important thing here is that @objc attribute opens the possibility of using optional methods and properties in protocols, but it also closes the door on using those @objc protocols with structs and enums. This is because, as with Objective-C protocols, any protocol that has the @objc attribute can only be adopted by classes, not structs or enums.
@objc protocol Optional {

    optional func youMightLikeToUseThis()

}

class OptionalClass: Optional {

}

Mixing optional with required protocol elements

So now we know how to create optional properties and methods in our protocols, and the price that must be paid, we can go ahead and mix and match optionals and non-optionals at will
@objc protocol Optional {
    optional var optionalStr:String{get set}
    var requiredStr:String
    optional func youMightLikeToUseThis()
    func youMustUseThis()
}

class OptionalClass: Optional {
    var requiredStr:String = ""
    func youMustUseThis() {
        println("OK, I did")
    }

}


var a = OptionalClass()
a.youMustUseThis() // prints "OK, I did"
and the compiler will be happy.

But what about generic functions?

Generic functions rely on protocols to know which methods can be used with generic types. So what would happen if we tried to call an optional method when it isn't implemented within a class that adopts the protocol? Well it turns out we can't and the compiler suggests that we add an exclamation mark to force unwrap our method, e.g. t.youMightLikeToUseThis!(), but if we did this and the optional method wasn't implemented our app would crash when the generic function called it. So let's instead write t.youMightLikeToUseThis?().
@objc protocol Optional {
    optional var optionalStr:String{get set}
    var requiredStr:String {get set}
    optional func youMightLikeToUseThis()->String
    func youMustUseThis()->String
}

class OptionalClass: Optional {
    var requiredStr:String = " "
    func youMustUseThis()->String {
        return "method available"
    }

}


var a = OptionalClass()
a.youMustUseThis() // returns "method available"


func OptionalGenericFunction(t:T) -> String {
 return t.youMightLikeToUseThis?() ?? "method not available"
}

OptionalGenericFunction(a) // returns "method not available"
Reading through the code you'll also notice that I've used the nil coalescing operator (??) to makes sure that the generic function now always returns a String (so that the function itself doesn't need to return an optional).

Note: the generic function could return an optional String? but I am simply choosing not to do this in this instance.
Endorse on Coderwall

Comments