Is it possible in Swift? If not then is there a workaround to do it?
This question is related to
ios
swift
optional-parameters
swift-protocols
swift-extensions
I think that before asking how you can implement an optional protocol method, you should be asking why you should implement one.
If we think of swift protocols as an Interface in classic object oriented programming, optional methods do not make much sense, and perhaps a better solution would be to create default implementation, or separate the protocol into a set of protocols (perhaps with some inheritance relations between them) to represent the possible combination of methods in the protocol.
For further reading, see https://useyourloaf.com/blog/swift-optional-protocol-methods/, which gives an excellent overview on this matter.
The other answers here involving marking the protocol as "@objc" do not work when using swift-specific types.
struct Info {
var height: Int
var weight: Int
}
@objc protocol Health {
func isInfoHealthy(info: Info) -> Bool
}
//Error "Method cannot be marked @objc because the type of the parameter cannot be represented in Objective-C"
In order to declare optional protocols that work well with swift, declare the functions as variables instead of func's.
protocol Health {
var isInfoHealthy: (Info) -> (Bool)? { get set }
}
And then implement the protocol as follows
class Human: Health {
var isInfoHealthy: (Info) -> (Bool)? = { info in
if info.weight < 200 && info.height > 72 {
return true
}
return false
}
//Or leave out the implementation and declare it as:
//var isInfoHealthy: (Info) -> (Bool)?
}
You can then use "?" to check whether or not the function has been implemented
func returnEntity() -> Health {
return Human()
}
var anEntity: Health = returnEntity()
var isHealthy = anEntity.isInfoHealthy(Info(height: 75, weight: 150))?
//"isHealthy" is true
There are two ways you can create optional method in swift protocol.
1 - The first option is to mark your protocol using the @objc attribute. While this means it can be adopted only by classes, it does mean you mark individual methods as being optional like this:
@objc protocol MyProtocol {
@objc optional func optionalMethod()
}
2 - A swiftier way: This option is better. Write default implementations of the optional methods that do nothing, like this.
protocol MyProtocol {
func optionalMethod()
func notOptionalMethod()
}
extension MyProtocol {
func optionalMethod() {
//this is a empty implementation to allow this method to be optional
}
}
Swift has a feature called extension that allow us to provide a default implementation for those methods that we want to be optional.
Put the @optional
in front of methods or properties.
To illustrate the mechanics of Antoine's answer:
protocol SomeProtocol {
func aMethod()
}
extension SomeProtocol {
func aMethod() {
print("extensionImplementation")
}
}
class protocolImplementingObject: SomeProtocol {
}
class protocolImplementingMethodOverridingObject: SomeProtocol {
func aMethod() {
print("classImplementation")
}
}
let noOverride = protocolImplementingObject()
let override = protocolImplementingMethodOverridingObject()
noOverride.aMethod() //prints "extensionImplementation"
override.aMethod() //prints "classImplementation"
if you want to do it in pure swift the best way is to provide a default implementation particullary if you return a Swift type like for example struct with Swift types
example :
struct magicDatas {
var damagePoints : Int?
var manaPoints : Int?
}
protocol magicCastDelegate {
func castFire() -> magicDatas
func castIce() -> magicDatas
}
extension magicCastDelegate {
func castFire() -> magicDatas {
return magicDatas()
}
func castIce() -> magicDatas {
return magicDatas()
}
}
then you can implement protocol without defines every func
A pure Swift approach with protocol inheritance:
//Required methods
protocol MyProtocol {
func foo()
}
//Optional methods
protocol MyExtendedProtocol: MyProtocol {
func bar()
}
class MyClass {
var delegate: MyProtocol
func myMethod() {
(delegate as? MyExtendedProtocol).bar()
}
}
Since there are some answers about how to use optional modifier and @objc attribute to define optional requirement protocol, I will give a sample about how to use protocol extensions define optional protocol.
Below code is Swift 3.*.
/// Protocol has empty default implementation of the following methods making them optional to implement:
/// `cancel()`
protocol Cancelable {
/// default implementation is empty.
func cancel()
}
extension Cancelable {
func cancel() {}
}
class Plane: Cancelable {
//Since cancel() have default implementation, that is optional to class Plane
}
let plane = Plane()
plane.cancel()
// Print out *United Airlines can't cancelable*
Please notice protocol extension methods can't invoked by Objective-C code, and worse is Swift team won't fix it. https://bugs.swift.org/browse/SR-492
How to create optional and required delegate methods.
@objc protocol InterViewDelegate:class {
@objc optional func optfunc() // This is optional
func requiredfunc()// This is required
}
Here is a concrete example with the delegation pattern.
Setup your Protocol:
@objc protocol MyProtocol:class
{
func requiredMethod()
optional func optionalMethod()
}
class MyClass: NSObject
{
weak var delegate:MyProtocol?
func callDelegate()
{
delegate?.requiredMethod()
delegate?.optionalMethod?()
}
}
Set the delegate to a class and implement the Protocol. See that the optional method does not need to be implemented.
class AnotherClass: NSObject, MyProtocol
{
init()
{
super.init()
let myInstance = MyClass()
myInstance.delegate = self
}
func requiredMethod()
{
}
}
One important thing is that the optional method is optional and needs a "?" when calling. Mention the second question mark.
delegate?.optionalMethod?()
In Swift 3.0
@objc protocol CounterDataSource {
@objc optional func increment(forCount count: Int) -> Int
@objc optional var fixedIncrement: Int { get }
}
It will save your time.
To define Optional
Protocol
in swift you should use @objc
keyword before Protocol
declaration and attribute
/method
declaration inside that protocol.
Below is a sample of Optional Property of a protocol.
@objc protocol Protocol {
@objc optional var name:String?
}
class MyClass: Protocol {
// No error
}
Define function in protocol and create extension for that protocol, then create empty implementation for function which you want to use as optional.
Here's a very simple example for swift Classes ONLY, and not for structures or enumerations. Note that the protocol method being optional, has two levels of optional chaining at play. Also the class adopting the protocol needs the @objc attribute in its declaration.
@objc protocol CollectionOfDataDelegate{
optional func indexDidChange(index: Int)
}
@objc class RootView: CollectionOfDataDelegate{
var data = CollectionOfData()
init(){
data.delegate = self
data.indexIsNow()
}
func indexDidChange(index: Int) {
println("The index is currently: \(index)")
}
}
class CollectionOfData{
var index : Int?
weak var delegate : CollectionOfDataDelegate?
func indexIsNow(){
index = 23
delegate?.indexDidChange?(index!)
}
}
Slightly off topic from the original question, but it builds off Antoine’s idea and I thought it might help someone.
You can also make computed properties optional for structs with protocol extensions.
You can make a property on the protocol optional
protocol SomeProtocol {
var required: String { get }
var optional: String? { get }
}
Implement the dummy computed property in the protocol extension
extension SomeProtocol {
var optional: String? { return nil }
}
And now you can use structs that do or don’t have the optional property implemented
struct ConformsWithoutOptional {
let required: String
}
struct ConformsWithOptional {
let required: String
let optional: String?
}
I’ve also written up how to do optional properties in Swift protocols on my blog, which I’ll keep updated in case things change through the Swift 2 releases.
optional
keyword prior to each method. One option is to store them as optional function variables:
struct MyAwesomeStruct {
var myWonderfulFunction : Optional<(Int) -> Int> = nil
}
let squareCalculator =
MyAwesomeStruct(myWonderfulFunction: { input in return input * input })
let thisShouldBeFour = squareCalculator.myWonderfulFunction!(2)
In Swift 2 and onwards it's possible to add default implementations of a protocol. This creates a new way of optional methods in protocols.
protocol MyProtocol {
func doSomethingNonOptionalMethod()
func doSomethingOptionalMethod()
}
extension MyProtocol {
func doSomethingOptionalMethod(){
// leaving this empty
}
}
It's not a really nice way in creating optional protocol methods, but gives you the possibility to use structs in in protocol callbacks.
I wrote a small summary here: https://www.avanderlee.com/swift-2-0/optional-protocol-methods/
Source: Stackoverflow.com