Why do we add protocol conformance with extensions? - swift

If I have a class Christmas, and a protocol Merry, to make Christmas conform to Merry, many people would do it this way:
class Christmas {
...
}
extension Christmas: Merry {
...
}
It's also encouraged by Apple.
However, isn't it more convenient to just make the class conform to protocol when it's defined? Like this:
class Christmas: Merry {
...
}
What's the difference between the 2 methods?

They are different coding styles. The first option
class Christmas {
...
}
extension Christmas: Merry {
...
}
is cleaner when you're looking at the whole class. You can instantly see all the protocol implementations the class conforms to.
Using the second option you put the implementation of the protocol inside the class mixing it with the class methods. However, if you use
//MARK: -
the code becomes not less clean, than when you use extensions. For example:
protocol Merry: class {
func celebrate()
}
class Cristmas: NSObject, Merry {
private var santa: AnyObject?
//MARK: - Private Methods
private func callSanta() {
//calling Santa
}
//MARK: - Merry Implementation
func celebrate() {
//celebration starts here
}
}
and when looking at the whole class you clearly see the separation of the protocol implementation:
The functionality of both options is the same.

There is difference between class conforms to protocol and the extension.
At the time of writing your class, you knew this should conforms to protocol then you can use class conforms to protocol. However, extensions are mean to extend functionality of existing classes. After writing your class and using it for a year, you need to add some additional feature to your class so instead of modify class, you can simply extend the class. Extension is not just for your classes, you can extend the behavior of every class available to you(native frameworks, third party libraries).

There is a little difference. The first one confirms to protocol as you expected. Coming to second one that also confirms to protocol and in addition to that methods writing in extensions
extension Christmas: Merry {
...
}
like this will make those methods available through out project with that Class name "Christmas"

Related

How to do?I want a protocol that can only be followed by two classes

I want a protocol that can only be followed by two classes。(ClassA or ClassB).
protocol MyProtocol where Self: ClassA || ClassB {
}
This requirement almost certainly indicates a design problem. If any piece of your system cares what is implementing the protocol, then the protocol does not capture the whole interface. For example, if at any point you use as? ClassA, then this is a dangerous use of protocols.
It is impossible in Swift to have a protocol that I can see but that I cannot implement. There are languages like Go where it's possible (though still not in exactly the way you describe), but it's impossible in Swift today. As #MartinR notes, the answer by J. Doe doesn't actually change anything. Outside parties can still just implement both protocols.
With that said, it's possible to achieve things very similar to what you're describing.
First, and most obviously: use access controls.
private protocol MyProtocol {}
public class ClassA: MyProtocol {}
public class ClassB: MyProtocol {}
This works if all the classes and protocol are in one file. If not, put them all in a framework and use internal rather than private. Now nothing outside this file/module can implement MyProtocol. The limitation is that MyProtocol is also can't be seen outside the file/module.
This can be resolved by lifting a struct:
public struct MyStruct: MyProtocol {
private let value: MyProtocol
public init(classA: ClassA) { value = classA }
public init(classB: ClassB) { value = classB }
// Methods to conform to MyProtocol by forwarding to value
}
With this, it's impossible to generate a MyStruct that is initialized with anything but a ClassA or ClassB.
Alternately, if you really literally mean "ClassA or ClassB" that's not a struct or a protocol. That's a enum:
enum MyEnum {
case classA(ClassA)
case classB(ClassB)
}

Swift protocol to only implemented by specific classes

I want to create a protocol which is only adopted by a specific class and its subClassses in swift.
I know i can use protocol extensions like this
protocol PeopleProtocol: class {
}
extension PeopleProtocol where Self: People {
}
But the method that will go in my protocol will be an init method which will be implemented by a class or its subClasess and will return only some specific type of objects.
some thing like this.
protocol PeopleProtocol: class {
init() -> People
}
or i can do some thing like this
extension PeopleProtocol where Self : People {
init()
}
But there are two problems,
In the first approach if i put an init method in the protocol it don't allow me to put a return statement there like -> People in the first approach.
In the second approach i have to provide a function body in the protocol extensions, so this thing will be out of question, as i don't know what specific type to return for this general implementation.
So any suggestions how i can call an init method and do either:
Let the protocol (not protocol extension) to be implemented by only specific classe and its subClasses.
Or return an instance of a certain from protocol extension method without giving its body.
You could add a required method that you only extend for the appropriate classes.
for example:
protocol PeopleProtocol
{
var conformsToPeopleProtocol:Bool { get }
}
extension PeopleProtocol where Self:People
{
var conformsToPeopleProtocol:Bool {return true}
}
class People
{}
class Neighbours:People
{}
extension Neighbours:PeopleProtocol // this works
{}
class Doctors:People,PeopleProtocol // this also works
{}
class Dogs:PeopleProtocol // this will not compile
{}
This could easily be circumvented by a programmer who would want to, but at least it will let the compiler warn you if you try to apply the protocol to other classes.

Swift extension for selected class instance

In Objective-C category, you can bring in the extended capability introduced by the category methods by including the header of the category in your class.
It seems like all Swift extensions are automatically introduced without import. How do you achieve the same thing in Swift?
For example:
extension UIView {
// only want certain UIView to have this, not all
// similar to Objective-C, where imported category header
// will grant the capability to the class
func extraCapability() {
}
}
Define a protocol that will serve as a selection, wether the extensions should be available or not:
protocol UIViewExtensions { }
then define an extension for the protocol, but only for subclasses of UIView (the other way around won't work):
extension UIViewExtensions where Self: UIView {
func testFunc() -> String { return String(tag) }
}
A class that is defined to have the protocol will also have the extension:
class A: UIView, UIViewExtensions { }
A().testFunc() //has the extension
And if it is not defined to have the protocol, it will also not have the extension:
class B: UIView {}
B().testFunc() //execution failed: MyPlayground.playground:17:1: error: value of type 'B' has no member 'testFunc'
UPDATE
Since protocol extensions don't do class polymorphism, if you need to override functions, the only thing I can think of is to subclass:
class UIViewWithExtensions: UIView {
override func canBecomeFocused() -> Bool { return true }
}
UIViewWithExtensions().canBecomeFocused() // returns true
this could also be combined with the extension, but I don't think it would still make much sense anymore.
You can make extensions private for a particular class by adding private before the extension like so
private extension UIView {
func extraCapability() {
}
}
This will mean it can only be used in that particular class. But you will need to add this to each class that requires this extension. As far as I know there is no way to import the extension like you can in Obj-c
NOTE
Private access in Swift differs from private access in most other languages, as it’s scoped to the enclosing source file rather than to the enclosing declaration. This means that a type can access any private entities that are defined in the same source file as itself, but an extension cannot access that type’s private members if it’s defined in a separate source file.
According to Apple, here, it does not appear you can make extensions private in separate files.
You can create a private extension in the same source file.

How to require that a protocol can only be adopted by a specific class

I want this protocol:
protocol AddsMoreCommands {
/* ... */
}
only to be adopted by classes that inherit from the class UIViewController. This page tells me I can specify that it is only adopted by a class (as opposed to a struct) by writing
protocol AddsMoreCommands: class {
}
but I cannot see how to require that it is only adopted by a particular class. That page later talks about adding where clauses to protocol extensions to check conformance but I cannot see how to adapt that either.
extension AddsMoreCommands where /* what */ {
}
Is there a way to do this?
Thanks!
protocol AddsMoreCommands: class {
// Code
}
extension AddsMoreCommands where Self: UIViewController {
// Code
}
This can also be achieved without an extension:
protocol AddsMoreCommands: UIViewController {
// code
}
Which is exactly the same as:
protocol AddsMoreCommands where Self: UIViewController {
// code
}
I usually use the first option, IIRC I read a while ago on the Swift docs that that is the recomended way when the constraint is Self, if is other constraint such as associate types is when where can be used.
Notice that since UIViewController is a class too, this protocol can be implemented for weak properties such as delegates.
EDITED 2021/01/05: Previous posted solution had a warning, I have removed it and use this one which does not produce any warning.
Because of an issue in the previous answer I ended up with this declaration:
protocol AddsMoreCommands where Self : UIViewController {
// protocol stuff here
}
no warnings in Xcode 9.1
Now in Swift 5 you can achieve this by:
protocol AddsMoreCommands: UIViewController {
/* ... */
}
Quite handy.

A way to inherit from multiple classes

I have two classes I want to use in my new class. The first one implements a swipe to delete and the second enables a long press gesture:
class DeleteItem: UITableViewCell {
}
class OpenDetail: UITableViewCell {
}
Since Swift doesn't allow a class to inherit from multiple classes the following example obviously won't work:
class ItemViewCell: DeleteItem, OpenDetail {
}
So in order to create ItemViewCell and having both options, I'll have to have one of the classes to inherit from each other:
class DeleteItem: UITableViewCell {
}
class OpenDetail: DeleteItem {
}
class ItemViewCell: OpenDetail {
}
The problem is, if I only want the long press gesture I'll have to create a new class without inheriting from DeleteItem. Is there a better way of doing this?
This is the perfect case for using Protocols and Protocol extension. A swift protocol is like an interface in Java for example. A protocol can define a set of functions which has to be implemented by the entities which want to conform to this protocol, moreover a protocol can define properties which has to be present in these entities too. For example:
protocol ItemDeleter {
var deletedCount: Int {get set}
func deleteItem(item: ItemType)
}
The problem is, that each entity would have to provide its own implementation of func deleteItem(item: ItemType) even if multiple entities share the same logic of deleting an item, this where a protocol extension comes in handy. For example:
extension ItemDeleter {
func deleteItem(item: ItemType) {
// logic needed to delete an item
// maybe incremented deletedCount too
deletedCount++
}
}
Then you could make your ItemViewCell conform to the ItemDeleter protocol, in this case all you need is to make sure that ItemViewCell has a property deletedCount: Int. It does not need to provide an implementation for func deleteItem(item: ItemType) as the protocol itself provides a default implementation for this function, however you can override it in your class, and the new implementation will be used. The same applies for DetailOpener protocol.