How to define optional methods in a Swift protocol with Swift parameters? - ios

TL;DR
How can I define optional methods in a swift protocol that accept custom typed parameters?
The case
I understand that the way to define optional methods in a swift protocol is using the #objc flag. Like so:
#objc protocol someSweetProtocol {
optional func doSomethingCool()
}
But when I wanted to use my custom type for the parameter, like so:
#objc protocol someSweetProtocol {
optional func doSomethingCool(🚶🏼: HSCoolPerson)
}
I got this error:
Which is not cool.
How can this problem be solved? Also can you explain why this is happening?
Addendum
This is how HSCoolPerson is defined:
class HSCoolPerson {
...
...
...
}
Nothing special there...

The problem is this:
class HSCoolPerson {
// ...
}
As the error message plainly tells you, that type, the class HSCoolPerson, is completely invisible to Objective-C. And a protocol optional method is an Objective-C language feature; Swift merely borrows it, as it were. (That's why you have to say #objc protocol to get this feature.) So any time you want to define a protocol optional method, you have to do it in a way that Objective-C can understand, because it is Objective-C that is going to do the work for you.
To expose this class to Objective-C, simply derive it from NSObject:
class HSCoolPerson : NSObject {
// ...
}
Problem solved.

Put the default implementations in an extension, like so:
class HSCoolPerson {}
protocol SomeSweetProtocol {
func doSomethingCool()
}
extension SomeSweetProtocol {
func doSomethingCool(🚶🏼: HSCoolPerson) {
// default implementation here
}
}
class SomeSweetClass: SomeSweetProtocol {
// no implementation of doSomethingCool(_:) here, and no errors
}

you can declare func like that in protocol
#objc optional func doSomethingCool(🚶🏼: HSCoolPerson)

Related

How does one specific a protocol in a function parameter?

I'm writing a factory class that is trying to work with custom protocol defined functions. The compiler throws an error, because I don't know how to add a protocol definition to a function parameter.
Example:
protocol MyCustomFunctions {
func customFunction()
}
class MyVC: UIViewController, MyCustomFunctions {
func customFunction() {}
}
class Factory {
func createButton(specificVC: UIViewController) // need protocol here
{
specificVC.customFunction() // error thrown
}
}
How can one specific a protocol during a variable definition?
Or is there another way?
First of all ,convention says classes start with a Capital letter.
class MyVC: UIViewController, MyCustomFunctions {
func customFunction() {}
}
Then what you need is the correct type in the argument
class factory: NSObject {
func createButton(specificVC: MyVC) // you need a class that conforms to protocol here.
{
specificVC.customFunction() // no error anymore
}
}
You have another option. You can simply promise in the argument that you won't disclose the full type of the object ,you will only say it's an opaque object that conforms to protocol.
class factory: NSObject {
func createButton(specificVC: MyCustomFunctions) // you need a class that conforms to protocol here.
{
specificVC.customFunction() // no error anymore
}
}
BONUS:
The way you could have reasoned about this and find an answer is this>
Error is thrown when I call specificVC.customFunction()...Hmmm...so this object can only run this function if it is of type that actually HAS the function. So let's take a look at the argument type - UIViewController - ..UIViewController certainly doesn't have this function. It's the MyVC or the Protocol.
Type safety in Swift is very strict. Just "follow the type flow" and you will be good.

How can I create a Set of delegate protocol items in Swift?

Let's assume I have five UIView objects which all conform to a particular protocol. I have an object which should maintain a list of these objects, and message them all when necessary.
protocol MyProtocol: AnyObject {
func doSomething()
}
The problem is, when I go to add these UIViews to a Set variable, the compiler produces an error because MyProtocol does not conform to Hashable. I can understand the reasoning for this, can anyone think of good ways to overcome this? In the meantime I considered using NSHashTable instead, but you lose the nice enumeration features of Sets.
Updating answer to post some sample code (this is still not working)
protocol MyProtocol: class, AnyObject {
func doSomething()
}
class MyClass {
var observers: Set<MyProtocol> = Set<MyProtocol>()
}
As you are defining protocol for class so you need to write 'class' keyword before inheriting any other protocol:
protocol MyProtocol: AnyObject, Hashable{
func doSomething()
}
class MyClass<T: MyProtocol> {
var observers: Set<T> = Set<T>()
}
Change your protocol to this and it will work fine.
You can refer Apple Documentation for further details.

Swift Declare Class Func in Protocol

I had following confusion. As far as I know the main difference between static and class keywords when declaring method is that the second one could be overridden in subclasses.
The problem
However when I declare a protocol in Swift 1.2 like this:
protocol MyProtocol
{
class func dummyClassMethod()
}
compiler gives an error:
Class methods are only allowed within classes; use 'static' to declare
a static method
The error is pretty descriptive as obviously MyProtocol is not a class, however I want to make a class func part of the protocol.
What I've tried
I've found that if I declare interface in protocol as static, compiler is happy and I could use this static method in all classes that adopt this protocol:
protocol MyProtocol
{
static func dummyClassMethod()
}
The question
So my question basically is is this right? This declaration states that my class method cannot be overridden in children, however in my implementation I could write and use the following:
class ClassA: MyProtocol
{
class func dummyClassMethod() {
}
}
class ClassB: ClassA
{
override class func dummyClassMethod() {
}
}
and now my dummyClassMethod is not static anymore...
Compiler is Ok and everything works - but why?
Is it specific to the fact that interface itself is static, however
it's implementation is not?
Is there a better alternative for class func in protocols?
Objective-C solution
In ObjC this is pretty easy and compile & run flawlessly:
#protocol MyProtocol
+(void)dummyClassMethod;
#end
You can review Apple's Documentation (subsection Method Requirements).
There says:
As with type property requirements, you always prefix type method requirements with the static keyword when they are defined in a protocol. This is true even though type method requirements are prefixed with the class or static keyword when implemented by a class
In practice, You can do it as follow:
First, declare your protocol:
protocol SomeProtocol {
static func someMethod()
}
Then, in your class you've 2 options:
First:
class SomeClass : SomeProtocol {
class func someMethod()
}
Second:
class SomeClass : SomeProtocol {
static func someMethod()
}
I hope, this may clarify your doubt..
https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Protocols.html
A protocol defines a blueprint of methods, properties, and other
requirements that suit a particular task or piece of functionality.
The protocol doesn’t actually provide an implementation for any of
these requirements—it only describes what an implementation will look
like. The protocol can then be adopted by a class, structure, or
enumeration to provide an actual implementation of those requirements.
After this protocol definition it becomes reasonable that
As with type property requirements, you always prefix type method
requirements with the static keyword when they are defined in a
protocol. This is true even though type method requirements are
prefixed with the class or static keyword when implemented by a class...
To make protocol method static and final implement that method with static keyword
class ClassA: MyProtocol{
static func dummyClassMethod() {
}
}
and now you cant override dummyClassMethod function anymore. If you want to prevent overriding only you must declare protocol method as final. About class functions, they were not fully supported in Swift 1.0 and now in Swift 1.2 I think that they are moving towards static functions

Check if optional protocol method is implemented in Swift?

I have a swift protocol:
#objc protocol SomeDelegate {
optional func myFunction()
}
I one of my classes I did:
weak var delegate: SomeDelegate?
Now I want to check if the delegate has myFunction implemented.
In objective-c I can do:
if ([delegate respondsToSelector:#selector(myFunction)]) {
...
}
But this is not available in Swift.
Edit: This is different from: What is the swift equivalent of respondsToSelector? I focus on class protocols not on classes.
How do I check if my delegate has an optional method implemented?
Per The Swift Programming Language:
You check for an implementation of an optional requirement by writing
a question mark after the name of the requirement when it is called,
such as someOptionalMethod?(someArgument). Optional property
requirements, and optional method requirements that return a value,
will always return an optional value of the appropriate type when they
are accessed or called, to reflect the fact that the optional
requirement may not have been implemented.
So the intention is not that you check whether the method is implemented, it's that you attempt to call it regardless and get an optional back.
You can do
if delegate?.myFunction != nil {
}
I've found it successful to add an extension to the protocol that defines basic default implementation and then any class implementing the protocol need only override the functions of interest.
public protocol PresenterDelegate : class {
func presenterDidRefreshCompleteLayout(presenter: Presenter)
func presenterShouldDoSomething(presenter: Presenter) -> Bool
}
then extend
extension PresenterDelegate {
public func presenterDidRefreshCompleteLayout(presenter: Presenter) {}
public func presenterShouldDoSomething(presenter: Presenter) -> Bool {
return true
}
}
Now any class needing to conform to the PresenterDelegate protocol has all functions already implemented, so it's now optional to override it's functionality.
I normally implement it like this:
self.delegate?.myFunction?()
if the delegate methods returns a value:
var result = defaultValue
if let delegateResult = self.delegate?.myFunction?() else {
result = delegateResult
}
//do something with result
Declaration
#objc public protocol nameOfDelegate: class {
#objc optional func delegateMethod(_ varA: int, didSelect item: Item)
}
Implimetation
if let delegate = nameOfDelegate {
delegate.delegateMethod?(1, didDeselect: node)
}
I know this question is 5 years old, but I would like to share what I found. My solution works as of 2021, XCode 11+, Swift 5.
Say I wanted to figure out whether the function sign follows the GIDSignInDelegate protocol and also know what all the optional functions for GIDSignInDelegate are.
I have to look at the source code of the GIDSignIn module, and this is how.
Click on jump to definition on the main module that is imported. It will lead to a file like this:
Copy the entire line, import GoogleSignIn.GIDSignIn and paste it in the ViewController or whatever .swift file (doesn't really matter).
Within the swift file, right click on the GIDSignIn part of the import line GoogleSignIn.GIDSignIn and jump to definition. This will lead you to the actual module with all the available functions (the functions not marked optional may be stubs, which are required functions in the delegate protocol):
From this file, I can see that there is a sign function that is a stub of GIDSignInDelegate and an optional sign function that is implemented as a method overload.
I used this for GIDSignInDelegate, but you can use the same method to figure out whether any function follows any delegate protocol.

Override var conforming to a protocol with a var conforming to a child of the overridden var protocol

This is my inheritance structure
Protocols
protocol BaseProtocol {
}
protocol ChildProtocol: BaseProtocol {
}
Classes
class BaseClass: NSObject {
var myVar: BaseProtocol!
}
class ChildClass: BaseClass {
override var myVar: ChildProtocol!
}
I'm receiving a compiler error:
Property 'myVar' with type 'ChildProtocol!' cannot override a property with type 'BaseProtocol!'
What is the best approach to achieve this?
UPDATE
I updated the question trying to implement the solution with generics but it does not work :( This is my code (now the real one, without examples)
Protocols
protocol TPLPileInteractorOutput {
}
protocol TPLAddInteractorOutput: TPLPileInteractorOutput {
func errorReceived(error: String)
}
Classes
class TPLPileInteractor<T: TPLPileInteractorOutput>: NSObject, TPLPileInteractorInput {
var output: T!
}
And my children
class TPLAddInteractor<T: TPLAddInteractorOutput>: TPLPileInteractor<TPLPileInteractorOutput>, TPLAddInteractorInput {
}
Well, inside my TPLAddInteractor I can't access self.output, it throws a compiler error, for example
'TPLPileInteractorOutput' does not have a member named 'errorReceived'
Besides that, when I create the instance of TPLAddInteractor
let addInteractor: TPLAddInteractor<TPLAddInteractorOutput> = TPLAddInteractor()
I receive this other error
Generic parameter 'T' cannot be bound to non-#objc protocol type 'TPLAddInteractorOutput'
Any thoughts?
#tskulbru is correct: it can't be done, and this has nothing to do with your protocols. Consider the example below, which also fails…this time with Cannot override with a stored property 'myVar':
class Foo {
}
class Goo: Foo {
}
class BaseClass: NSObject {
var myVar: Foo!
}
class ChildClass: BaseClass {
override var myVar: Foo!
}
To understand why, let's reexamine the docs:
Overriding Properties
You can override an inherited instance or class property to provide
your own custom getter and setter for that property, or to add
property observers to enable the overriding property to observe when
the underlying property value changes.
The implication is that if you are going to override a property, you must write your own getter/setter, or else you must add property observers. Simply replacing one variable type with another is not allowed.
Now for some rampant speculation: why is this the case? Well, consider on the one hand that Swift is intended to be optimized for speed. Having to do runtime type checks in order to determine whether your var is in fact a Foo or a Bar slows things down. Then consider that the language designers likely have a preference for composition over inheritance. If both of these are true, it's not surprising that you cannot override a property's type.
All that said, if you needed to get an equivalent behavior, #tskulbru's solution looks quite elegant, assuming you can get it to compile. :)
I don't think you can do that with protocols
The way i would solve the problem you are having is with the use of generics. This means that you essentially have the classes like this (Updated to a working example).
Protocols
protocol BaseProtocol {
func didSomething()
}
protocol ChildProtocol: BaseProtocol {
func didSomethingElse()
}
Classes
class BaseClass<T: BaseProtocol> {
var myProtocol: T?
func doCallBack() {
myProtocol?.didSomething()
}
}
class ChildClass<T: ChildProtocol> : BaseClass<T> {
override func doCallBack() {
super.doCallBack()
myProtocol?.didSomethingElse()
}
}
Implementation/Example use
class DoesSomethingClass : ChildProtocol {
func doSomething() {
var s = ChildClass<DoesSomethingClass>()
s.myProtocol = self
s.doCallBack()
}
func didSomething() {
println("doSomething()")
}
func didSomethingElse() {
println("doSomethingElse()")
}
}
let foo = DoesSomethingClass()
foo.doSomething()
Remember, you need a class which actually implements the protocol, and its THAT class you actually define as the generic type to the BaseClass/ChildClass. Since the code expects the type to be a type which conforms to the protocol.
There are two ways you can go with your code, depending what you want to achieve with your code (you didn't tell us).
The simple case: you just want to be able to assign an object that confirms to ChildProtocol to myVar.
Solution: don't override myVar. Just use it in ChildClass. You can do this by design of the language Swift. It is one of the basics of object oriented languages.
Second case: you not only want to enable assigning instances of ChildProtocol, you also want to disable to be able to assign instances of BaseProtocol.
If you want to do this, use the Generics solution, provided here in the answers section.
If you are unsure, the simple case is correct for you.
Gerd

Resources