15
votes

Here I define a protocol in Swift:

protocol DrawViewProtocol: class{
    optional func drawViewDidEndEditing() // Warning!
}

And Compiler gave me an error.

Optional can only be applied to members of an @objc protocol

So what I understand is optional and required are only avaliable in Objective-C? Though, how to define a optional or required in pure Swift style ?

6
Pure Swift, hmm then Protocol Extensions may be the thing you need to check. I'm not sure if that will solve your problem. - Inder Kumar Rathore

6 Answers

45
votes

Swift doesn't allow protocols to have optional requirements-- if the protocol declares something, it's required. Objective-C has long had the idea of optional requirements, and Swift recognizes this when you use @objc when declaring the protocol. So using @objc is the easy way to get what you're after.

If you want a pure Swift solution, you need to add a protocol extension that includes default implementations of the methods. This doesn't make those methods optional, instead it says that any class that doesn't implement the method itself will use the default implementation instead. They're sort of optional in that classes don't have to implement them, but not really optional since that's only because a default implementation is available.

That would look something like this:

protocol DrawViewProtocol : class{
    func drawViewDidEndEditing()
}

extension DrawViewProtocol {
    func drawViewDidEndEditing() {}
}

class MyClass : DrawViewProtocol {

}

class MyOtherClass : DrawViewProtocol {
    func drawViewDidEndEditing() {
        print("Foo")
    }
}

Now if I create an instance of MyClass and call drawViewDidEndEditing(), it uses the default implementation, which does nothing. If I create an instance of MyOtherClass, the same method call prints "Foo".

20
votes

In Swift 3 and Swift 4 use @objc for optional prototype

@objc protocol YourProtocolName: class {
    @objc optional func yourMethodName()
}
5
votes

From the apple's documentation : Even if you are not interoperating with Objective-C, you need to mark your protocols with the @objc attribute if you want to specify optional requirements.

Please see Optional Protocol Requirements section from this document.

4
votes

Although the above answers are actually right, they don't provide you with a pure-Swift answer.

The right way to do that in Swift would be to actually use protocols:

  • Define your first protocol, A, with only required properties, methods, ... you name it
  • Define a second protocol, B, with your so called "optional" properties
  • Hence, all your classes / protocols that need to be A-compliant will be.
  • Those which require "optional" compliance can be extended using compliance to protocol B.

Example:

protocol MyRequiredProtocol {
    var a: String { get }
    var b: String { get }

    func aMethod()
}

protocol MySoCalledOptionalProtocol {
    var c: String { get }

    func anotherMethod()
}


class MyFirstClass: MyRequiredProtocol {
    var a: String { return "a" }
    var b: String { return "b" }

    func aMethod() {
        // Do something
    }
}

class MySecondClass: MyRequiredProtocol, MySoCalledOptionalProtocol {
    var a: String { return "a" }
    var b: String { return "b" }

    var c: String { return "c" }

    func aMethod() {
        // Do something
    }

    func anotherMethod() {
        // Do something
    }
}
3
votes

You can accomplish it like this:

@objc protocol MyProtocol {

    optional func myMethod()

}
1
votes

Just add @objc before protocol this way:

@objc protocol FriendsTableDelegate {
    func didSelectFriend(friend: User) -> Void
    optional func didSelectFriend(friend: User, cell: FriendCell) -> Void
}