How to define optional methods in Swift protocol?

IosSwiftOptional ParametersSwift ProtocolsSwift Extensions

Ios Problem Overview


Is it possible in Swift? If not then is there a workaround to do it?

Ios Solutions


Solution 1 - Ios

1. Using default implementations (preferred).
protocol MyProtocol {
    func doSomething()
}

extension MyProtocol {
    func doSomething() {
        /* return a default value or just leave empty */
    }
}

struct MyStruct: MyProtocol {
    /* no compile error */
}

Advantages

  • No Objective-C runtime is involved (well, no explicitly at least). This means you can conform structs, enums and non-NSObject classes to it. Also, this means you can take advantage of powerful generics system.

  • You can always be sure that all requirements are met when encountering types that conform to such protocol. It's always either concrete implementation or default one. This is how "interfaces" or "contracts" behave in other languages.

Disadvantages

  • For non-Void requirements, you need to have a reasonable default value, which is not always possible. However, when you encounter this problem, it means that either such requirement should really have no default implementation, or that your you made a mistake during API design.

  • You can't distinguish between a default implementation and no implementation at all, at least without addressing that problem with special return values. Consider the following example:

    protocol SomeParserDelegate {
        func validate(value: Any) -> Bool
    }
    

    If you provide a default implementation which just returns true — it's fine at the first glance. Now, consider the following pseudo code:

    final class SomeParser {
        func parse(data: Data) -> [Any] {
            if /* delegate.validate(value:) is not implemented */ {
                /* parse very fast without validating */
            } else {
                /* parse and validate every value */
            }
        }
    }
    

    There's no way to implement such an optimization — you can't know if your delegate implements a method or not.

    Although there's a number of different ways to overcome this problem (using optional closures, different delegate objects for different operations to name a few), that example presents the problem clearly.


2. Using @objc optional.
@objc protocol MyProtocol {
    @objc optional func doSomething()
}

class MyClass: NSObject, MyProtocol {
    /* no compile error */
}

Advantages

  • No default implementation is needed. You just declare an optional method or a variable and you're ready to go.

Disadvantages

  • It severely limits your protocol's capabilities by requiring all conforming types to be Objective-C compatible. This means, only classes that inherit from NSObject can conform to such protocol. No structs, no enums, no associated types.

  • You must always check if an optional method is implemented by either optionally calling or checking if the conforming type implements it. This might introduce a lot of boilerplate if you're calling optional methods often.

Solution 2 - Ios

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/

Solution 3 - Ios

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?()

Solution 4 - Ios

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

Solution 5 - Ios

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

Solution 6 - Ios

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.

Solution 7 - Ios

  • You need to add optional keyword prior to each method.
  • Please note, however, that for this to work, your protocol must be marked with the @objc attribute.
  • This further implies that this protocol would be applicable to classes but not structures.

Solution 8 - Ios

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()
    }
}

Solution 9 - Ios

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"

Solution 10 - Ios

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.

Solution 11 - Ios

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.

Solution 12 - Ios

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.

Solution 13 - Ios

How to create optional and required delegate methods.

@objc protocol InterViewDelegate:class {

    @objc optional func optfunc()  //    This is optional
    func requiredfunc()//     This is required 

}

Solution 14 - Ios

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!)
    }

 }

Solution 15 - Ios

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

Solution 16 - Ios

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)

Solution 17 - Ios

Let's understand the difference first

First example - If you write UITableViewDataSource then you need to write two method forcefully - That's the swift way default Protocol

Second Example - If you write UITableViewDelegate and aware that it doesn't show the red error that please add all the delegate method. It's up to you that which method you want to use. we can called as optional method!

Let's understand this by an example

First Swift Way default Protocol approach

class ContactModel{
    var firstname: String?
    var lastname: String?
}

protocol ContactDataSource: AnyObject{
    func contactConfiguration(contact: ContactModel)
}

class ViewController: ContactDataSource{
    func contactConfiguration(contact: ContactModel) {
        print(contact)
    }
}

Second approach - optional protocol

@objc
class UserModel: NSObject{
    var firstname: String = ""
}

@objc protocol UserDataSource{
    func contactConfiguration(user: UserModel)
   @objc optional func userInfo(user: UserModel)
}

class ViewController: UserDataSource{
    func contactConfiguration(user: UserModel) {
        print(user)
    }
}

> Note: If you can see in optional protocal I haven't write userInfo method so its up to you. That mean With and without adding a method to the class > its working fine. - called as a optional method in protocol > > You must declare the class and protocol with the > @objc attribute, and it's only working with Class not struct!

Third approach - optional protocol using Extension

> Note: You can take Struct or Class

class UserModel{
    var firstname: String = ""
}

OR

struct UserModel{
    var firstname: String = ""
}

AND

protocol UserDataSource{
    func contactConfiguration(user: UserModel)
}

extension UserDataSource{
    func userInfo(user: UserModel){}
}

class myview: UserDataSource{
    func contactConfiguration(user: UserModel) {
        print(user)
    }
}

Solution 18 - Ios

Define function in protocol and create extension for that protocol, then create empty implementation for function which you want to use as optional.

Solution 19 - Ios

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

}

Solution 20 - Ios

Put the @optional in front of methods or properties.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionSelvinView Question on Stackoverflow
Solution 1 - IosakashivskyyView Answer on Stackoverflow
Solution 2 - IosAntoineView Answer on Stackoverflow
Solution 3 - IosRaphaelView Answer on Stackoverflow
Solution 4 - IosEddie.DouView Answer on Stackoverflow
Solution 5 - IosZagView Answer on Stackoverflow
Solution 6 - IosGautam SareriyaView Answer on Stackoverflow
Solution 7 - IosMehul ParmarView Answer on Stackoverflow
Solution 8 - IosguenisView Answer on Stackoverflow
Solution 9 - IoseLillieView Answer on Stackoverflow
Solution 10 - IosHimanshuView Answer on Stackoverflow
Solution 11 - IosememView Answer on Stackoverflow
Solution 12 - IosmatthewpalmerView Answer on Stackoverflow
Solution 13 - IosSaurabh SharmaView Answer on Stackoverflow
Solution 14 - IosBlessing LopesView Answer on Stackoverflow
Solution 15 - Iosp1ckl3View Answer on Stackoverflow
Solution 16 - IosOwlOCRView Answer on Stackoverflow
Solution 17 - IosYogesh PatelView Answer on Stackoverflow
Solution 18 - IosRishu GuptaView Answer on Stackoverflow
Solution 19 - IosAnkur GuptaView Answer on Stackoverflow
Solution 20 - IosshucaoView Answer on Stackoverflow