Swift property conforming with multiple protocols - ios

I have custom UIView (CustomView) conforming to two different protocols
protocol ResizableDelegate: class {
func view(view:UIView, didChangeHeight difference:CGFloat)
}
protocol Resizable: class {
var delegate:ResizableDelegate? { set get }
}
protocol TappableDelegate: class {
func viewDidTap(view:UIView)
}
protocol Tappable {
var delegate:TappableDelegate? { set get }
}
And I need to have a property in my CustomView class named delegate and conforming to these two protocols at the same time. I read Types conforming to multiple protocols in swift but that is not solving my problem.
I created this protocol
protocol CustomViewDelegate: ResizableDelegate, TappableDelegate {}
And then make my CustomView
class CustomView : UIView, Resizable, Tappable {
var delegate:CustomViewDelegate?
}
But that is causing me to get a message
Type 'CustomView' does not conform to protocol 'Resizable'
I don't want to have:
class CustomView : UIView, Resizable, Tappable {
var resizableDelegate:ResizableDelegate?
var TappableDelegate:TappableDelegate?
}
Is there any way two have only one delegate property that conforms to these two protocols at the same time? Im using swift 2.0, Xcode 7.

I guess you don't really need to declare Resizable and Tappable protocols. All you need is to delegate from your custom view to some other object, which confirms to both ResizableDelegate and TappableDelegate, right? If so, this should work for you:
protocol ResizableDelegate: class {
func view(view:UIView, didChangeHeight difference:CGFloat)
}
protocol TappableDelegate: class {
func viewDidTap(view:UIView)
}
class CustomView : UIView {
var delegate: (ResizableDelegate, TappableDelegate)?
}

Although you can leave things as is, I would strongly recommend changing the required properties to "tappableDelegate" and "resizableDelegate" thus having two separate properties in your View subclass.
Your specific use case may require adherence to both, but having the same naming means you would not be able to have different delegates.

Related

Swift UI use View in a Protocol (Protocol 'View' can only be used as a generic constraint because it has Self or associated type requirements)

I want to use View in a Protocol.
protocol Test {
var view: View { get }
}
Protocol 'View' can only be used as a generic constraint because it
has Self or associated type requirements
I just want to do the same thing as with my ViewController. Any idea?
protocol Test {
var viewController: UIViewController { get }
}
If I use an associated type, I get the error in my other protocols.
protocol Test2: Test { 
//STUB
}
Any idea how to solve this problem? Thanks :)
SwiftUI.View is a protocol, and because it uses Self (for example, in its body property), you cannot directly declare a property type as a View.
You can define an associated type on Test and constrain that type to be a View:
protocol Test {
associatedtype T: View
var view: T { get }
}
You can't directly use the protocol unless you declare it as associated type, but you can use the type erased AnyView instead:
protocol Test {
var view: AnyView { get }
}
Creating an AnyView instance might add some noise in the code, however it's easy to create.
Extending Cristik's solution:
protocol ViewFactoryProtocol {
func makeView(parameter: SomeType) -> AnyView
}

Subclass/Extend UIView so all other Views (UIImageView, UITextField ...) inherit upon creation

what is the suggested approach when I want to add a functionality to UIView so all views inside my app get those? As a matter of fact I need to add some stored properties too so an Extension is not possible. Since I need to deal with Textfields, ImageViews, Views (and who knows what else will come) I dont want to subclass every each of the too add that functionality, so the goal would be to make a subclass of UIView and all my controls (if its possible) get that functionality out of the box.
With an extension it would be easy, but as I said, I need to store some stuff too, so is this goal achievable with a subclass? Or what would be the right approach (maybe there is a third option)
Thanks
Why don't you define a protocol and provide default implementations in the protocol extension, then have UIView conform to that protocol? Here is an example:
protocol MyProto {
var someVar: Bool { get set }
func someFunc() -> Void
}
extension MyProto {
var someVar: Bool {
get {
// provide default implementation
return true
}
set {
}
}
func someFunc() -> Void {
// provide common implementation
}
}
extension UIView: MyProto {}
You can also use the where clause to constrain the default behaviour for a type.
extension MyProto where Self: UIControl {
var someVar: Bool {
get {
return isUserInteractionEnabled
}
set {
isUserInteractionEnabled = newValue
}
}
}
extension MyProto where Self: UITextField {
var someVar: Bool {
get {
return isFirstResponder
}
set {
newValue ? becomeFirstResponder() : resignFirstResponder()
}
}
}
TLDR; You can't do this and you will need to subclass each UI element that you want to introduce new properties to.
You can't do this (without access to the source code) as you would effectively be changing the class inheritance tree by injecting your own class between UIView and its subclasses.
Consider the implications if a language allowed this:
Class A defines a property, a
Class Binherits from Class A and defines a property b, which is fine because Class A does not have this property.
Class C inherits from Class B and has both a and b properties.
Now, what could happen if you could 'inject' Class A1 somehow 'below' Class A?
Class A1 could define a property, b, which is fine because Class A does not have this property
Class B now has a problem though, because its b clashes with the superclass b
Class C has a multiple-inheritance diamond-problem with property b
Of course, you only intend to add properties that don't clash (although you can't know this because you don't know of all possible subclass implementations) and don't need the subclasses to access your property, so the multiple inheritance
isn't an issue, but if such a feature were in a language, these potential issues would need to be addressed because you can't rely on everyone having the same intentions as you.

Protocol extension vs class extension in Swift

Assume there is a protocol Draggable, usually will be conformed by an UIView object
protocol Draggable {
drag()
}
We can either implement drag() in a protocol extension as option 1
// option 1
extension Draggable where Self: UIView {
func drag() {
// implementation
}
}
extension UIView: Draggable {} // added after #Rich Tolley's answer
Or we can implement drag() in a UIView extension as option 2
// option 2
extension UIView: Draggable {
func drag() {
// implementation
}
}
Here is my question:
Is there a difference between these two approaches (option 1 & option 2) ?
If yes, what's the difference and how to choose when we design a our project or library ?
And idea would be helpful.
Yes, there is a difference: (EDIT: or at least there was in the original version of this q, which didn't add extension UIView : Draggable {} to the end of option 1).
Option 1 creates a default implementation for instances of UIView that conform to Draggable. You still need to mark UIViews you wish to conform to Draggable as such in the declaration: class MyView : Draggable. Anything that conforms to Draggable but is not a UIView subclass will need to supply its own implementation.
Option 2 extends all UIViews to make them conform to Draggable. Nothing else can be a Draggable unless separate extensions are also written for those classes, or they are manually conformed to the protocol. There is no need to add Draggable in the class declaration.
The protocol extension is usually the better option. In this case this is obviously true since not all UIViews can be Draggable. Also, going down the protocol extension route means that you can create a Draggable object that is not a UIView subclass, if necessary (admittedly fairly unlikely, since most Cocoa controls are UIView subclasses - although not all -UIBarButtonItem isn't, strangely)
If you follow option 2, you will be adding unnecessary methods to UIView in a lot of cases, which is a violation of good object oriented design - specifically the Interface Segregation Principle (clients should not be forced to rely on methods they don't use
) - which is the 'I' in the SOLID principles
A protocol extension should be used when you want to implement functionality for more than just one class.
In this case you should use the extension UIView: Draggable as the Implementation is specific to the UIView class.
Assuming you have a protocol which provides location:
protocol Location {
var location: CGPoint { get set }
}
and you want every class which implements Location to conform to Draggable, then a protocol extension could be used:
extension Draggable where Self: Location {
func drag() {
}
}
For further reference, you should have a look at Protocol-Oriented Programming in Swift from the 2015 WWDC.

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.

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