How to define optional methods in Swift protocol?
IosSwiftOptional ParametersSwift ProtocolsSwift ExtensionsIos 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.
@objc optional
.
2. Using @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.