swift whats the difference between these protocols - ios

I've seen protocols been declared in two ways, but I don't get the difference.
Ex1:
protocol AddItemViewControllerDelegate {
func controller(controller: AddItemViewController, didAddItem: String)
}
Ex2:
protocol AddItemViewControllerDelegate: class {
func controller(controller: AddItemViewController, didAddItem: String)
}
So whats the difference?

From the docs:
You can limit protocol adoption to class types (and not structures or
enumerations) by adding the class keyword to a protocol’s inheritance
list. The class keyword must always appear first in a protocol’s
inheritance list, before any inherited protocols:
protocol SomeClassOnlyProtocol: class, SomeInheritedProtocol {
// class-only protocol definition goes here }
Note:
Use a class-only protocol when the behavior defined by that protocol’s
requirements assumes or requires that a conforming type has reference
semantics rather than value semantics.

if you want to declare a variable like this :
var aVar : AddItemViewControllerDelegate?
you have to do :
protocol AddItemViewControllerDelegate: class {
func controller(controller: AddItemViewController, didAddItem: String)
}

Related

Non-'#objc' method does not satisfy requirement of '#objc' protocol [duplicate]

This question already has answers here:
Non-'#objc' method does not satisfy optional requirement of '#objc' protocol
(3 answers)
Closed 1 year ago.
I've put the following into a Playground to try and understand this and I just don't:
import Foundation
#objc protocol Sample {
var value: Int { get set }
func increase()
func decrese()
}
extension Sample {
func increase() {
value += 1
}
func decrease() {
value -= 1
}
}
class Test: Sample {
var value: Int = 0
}
The error appears next to the class declaration for Test saying:
Non-'#objc' method 'increase()' does not satisfy requirement of '#objc' protocol 'Sample'
If I re-declare increase() and decrease() in the class then the warning is silenced. Or also if I remove the declarations from the protocol. Could someone please explain?
EDIT
I do need an Objective-C class to conform to this protocol as well, hence the #objc at the start.
The problem is that you’re defining these methods in a protocol extension. This is used to define a “default implementation” for a protocol (i.e. if a type doesn’t implement the method, the protocol’s implementation will be called).
But Objective-C doesn’t have the concept of default implementations for protocols. So it doesn’t makes sense to declare the protocol as #objc and have default implementations within the Swift protocol extension. An Objective-C class conforming to this protocol would never be able to enjoy these Swift default implementations.
The below code works with empty protocol methods' implementation in the Protocol extension class
import Foundation
protocol Sample {
var value: Int { get set }
func increase()
func decrease()
}
extension Sample {
func increase() { }
func decrease() { }
}
class Test: Sample {
var value: Int = 0
}
or if you want some default implementation of Sample protocol methods in the extension then use
import Foundation
protocol Sample {
var value: Int { get set }
func increase()
mutating func decrease()
}
extension Sample {
func increase() {
print("do anything")
}
mutating func decrease() {
value -= 1
}
}
class Test: Sample {
var value: Int = 0
}
mutating is added before the protocol method decrease() because it modifies the Protocol variable value.
If the Protocol extension doesn't modify any of the Protocol variable (e.g. increase()), then there is no need of mutating keyword

Not able to extend ObjC class using Protocol in swift

I am trying to extend an ObjC class for dependency injection using a protocol in swift , this class isn't owned by me so I cant make changes. For one of the method its working but for other Xcode always says that the class isn't confirming to the protocol and suggests me to add the method to the extension
Below is the declaration in ObjC header
- (BOOL) subscribeToTopic:(NSString *)topic
QoS:(AWSIoTMQTTQoS)qos
extendedCallback:(AWSIoTMQTTExtendedNewMessageBlock)callback;
Here is the protocol and its extension
protocol PopAWSIoTDataManagerProtocol {
func publishString(_ data:String, onTopic:String, QoS:AWSIoTMQTTQoS) -> Bool
func subscribeToTopic(_ topic: String, qoS: AWSIoTMQTTQoS, extendedCallback: (NSObject, String, Data) -> Void) -> Bool
}
extension AWSIoTDataManager : PopAWSIoTDataManagerProtocol {
}
Notice the error below it suggests me exactly same func to be added to extension which I already have added to main protocol
Not sure whats wrong , as I was able to add another method just fine.
Article used as a reference is this https://medium.com/flawless-app-stories/the-complete-guide-to-network-unit-testing-in-swift-db8b3ee2c327
You must confirm protocol PopAWSIoTDataManagerProtocol, cuz it extension of class AWSIoTDataManager
Or you can try this
extension PopAWSIoTDataManagerProtocol where Self: AWSIoTDataManager {
...
}
The protocol that you have defined has all function's to implemented as mandatory.
You need to define them as optional. Either you define them as optional or implement all of them which was the error image that you have attached is asking for.
#objc protocol PopAWSIoTDataManagerProtocol {
#objc optional func publishString(_ data:String, onTopic:String, QoS:AWSIoTMQTTQoS) -> Bool
#objc optional func subscribeToTopic(_ topic: String, qoS: AWSIoTMQTTQoS, extendedCallback: (NSObject, String, Data) -> Void) -> Bool
}
Default behavior of Protocol, when implemented is that you have to override all the methods. These are categorized as Protocol Requirements.
There are Optional Protocol Requirements , which do not have to be implemented by types that conform to the protocol.
To achieve Optional Protcol Requirements, the protocol and the requirement i.e the optional function must be marked as #objc.

Swift 3 Overload Operators for Protocols

I have a protocol that declares property of type Int. I also have few classes that conforms that Protocol, and now I need to overload operator + for all of them. Since operator + will work based on the property declared, I don't want to implement that operator in each class separately.
So I have
protocol MyProtocol {
var property: Int { get }
}
And I would want to have something like
extension MyProtocol {
static func +(left: MyProtocol, right: MyProtocol) -> MyProtocol {
// create and apply operations and return result
}
}
And actually I successfully did that, but trying to work with it I get an error ambiguous reference to member '+'.
When I move operator overload func to the each class separately, issue disappeared, but I'm still looking for a solution to make it works with Protocols.
Solved, by moving func +... outside of Extension, so it is just a method in the file where MyProtocol is declared
protocol MyProtocol {
var property: Int { get }
}
func +(left: MyProtocol, right: MyProtocol) -> MyProtocol {
// create and apply operations and return result
}

Protocol inheritance issue

I try to set up various protocols that work hand in hand. Unfortunately I cannot make them work the way I want. Looking at the following code, I think my goal is obvious: I want to require a class that conforms to a protocol X. If it conforms to protocol Y instead but protocol Y inherits from protocol X, it should be accepted as a conforming class too. Instead I receive the following compile error
Unable to infer associated type 'VC' for protocol 'ViewModelType'
Inferred type 'ExampleViewControllerType' (by matching requirement 'viewController') is invalid: does not conform to 'ViewType'
Current setup:
protocol ViewModelType: class {
associatedtype VC: ViewType
weak var viewController: VC! { get set }
}
class ExampleViewModel: ViewModelType {
weak var viewController: ExampleViewControllerType!
}
protocol ViewType: class { }
protocol ExampleViewControllerType: ViewType { }
class ExampleViewController: UIViewController, ExampleViewControllerType {
}
I can see what you are getting at with the 'transitive' protocols, however your error is caused by your associatedtype declaration of VC as seen in the error.
Unable to infer associated type 'VC' for protocol 'ViewModelType'
I think the compiler is having difficulty here maybe because its an innapropriate use of the associatedtype declaration.
An associatedtype can be thought of as a placeholder for an unknown type.
By defining VC as an associatedtype you are letting any class that inherits ViewModelType decide what type VC should be.
In ExampleViewModel class you do this by setting the type using typealias in the conforming class.
Your viewController can then be an ExampleViewControllerType without causing the 'inferred' error
protocol ViewModelType: class {
associatedtype VC
var viewController: VC! { get set }
}
class ExampleViewModel: ViewModelType {
typealias VC = ExampleViewControllerType
weak var viewController: ExampleViewControllerType!
}
protocol ViewType: class { }
protocol ExampleViewControllerType: ViewType { }
class ExampleViewController: UIViewController, ExampleViewControllerType {
}
No!! it can't be conforming class (If it conforms to protocol Y instead but protocol Y inherits from protocol X, it should be accepted as a conforming class too). A protocol can inherit one or more other protocols and can add further requirements on top of the requirements it inherits. The syntax for protocol inheritance is similar to the syntax for class inheritance. you cannot extend a protocol to conform to another protocol. only a class satisfy all of the requirements enforced by protocol. you could extend the protocol to provide default implementations.
extension Y {
// default implementations
}
for more Protocol Inheritance

Set and protocols in Swift

I would like to initialize a Set with values corresponding to the Hashable protocol and a custom protocol.
I tried :
protocol CustomProtocol: Hashable {}
let set = Set<CustomProtocol>()
But Xcode complains :
Using 'CustomProtocol' as a concrete type conforming to protocol
'Hashable' is not supported
How can I achieve that ?
Thanks in advance.
The immediate reason why you can't do what you want to do is that Hashable is a generic protocol. Thus it — or a protocol that derives from it — cannot be used as a Set's element type. A generic type can used only as a constraint in another generic. You will notice that you can't declare a Set<Hashable> either, even though a set's element type must conform to Hashable.
The simplest approach is to make, not a set of protocols, but a set of some object type. For example, if S is a struct that conforms to CustomProtocol (because it conforms to Hashable plus whatever else CustomProtocol entails), you can declare a set of S.
Example:
protocol CustomProtocol: Hashable {
}
func ==(lhs:S,rhs:S) -> Bool {
return lhs.name == rhs.name
}
struct S : CustomProtocol {
var name : String
var hashValue : Int { return name.hashValue }
}
let set = Set<S>()
If the problem you're trying to solve is that you want a collection of mixed types which are nevertheless in some way equatable to one another, then that is the very same problem solved by protocol extensions, as explained by the discussion in the Protocol-Oriented WWDC 2015 video.
But it would be simpler just to make all your types classes that derive from NSObject. You can still make them adopt some secondary protocol, of course, but the set won't be defined as a set of that protocol but of NSObject.
In Swift 3, one solution is to use the AnyHashable structure.
For instance, to create a Observers/Observable pattern, we could do :
protocol Observer {
func observableDidSomething(_ observable: Observable)
}
class Observable {
private var observersSet: Set<AnyHashable> = []
private var observers: [Observer] {
return observersSet.flatMap { $0 as? Observer }
}
func add<O>(_ observer: O) where O : Observer, O : Hashable {
observersSet.insert(observer)
}
func remove<O>(_ observer: O) where O : Observer, O : Hashable {
observersSet.remove(observer)
}
// ...
private func doSomething() {
// do something ...
observers.forEach { $0.observableDidSomething(self) }
}
}
Notice that I separate the Hashable protocol from my protocol Observer.

Resources