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

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.

Related

Difference when declaring swift protocol using inheritance from another protocol or using where Self

I still don't understand what is the difference when declaring a Swift protocol using inheritance:
protocol SubProtocol: SuperProtocol { ... }
or using where Self
protocol SubProtocol where Self: SuperProtocol { ... }
By doing this on these two ways the results are exactly the same, both options compile fine, and it works, SubProtocol will have the same stuff than SuperProtocol has. So what is the difference?
The only difference I can see is the semantic, one is more clear than the other (see example below). But this is my point of view and I would like to know if someone else thinks the same, or perhaps I am miss-understanding the whole thing.
Example:
protocol Progressable {
var isInProgress: Bool { get }
}
protocol Downloadable: Progressable {
func download()
}
protocol ProgressReporting where Self: Progressable {
func reportProgress() -> Bool
}
For me, Downloadable makes sense it inherits from Progressable, every download is progressable, so that is fine.
But ProgressReporting not necessary needs to inherit from Progressable, for me it would make more sense to constraint it by using where, this way the reader can know that whoever implements it, will need to conform to Progressable too (see the comments on the code below), here is when I think the semantic is different.
class MyClassA: Downloadable {
var isInProgress: Bool { return true }
func download() {}
func foo() {
/*
I have access to `self.isInProgress` because this class conforms `Downloadable`
which inherits from `Progressable`, so this makes sense
*/
_ = self.isInProgress
}
}
class MyClassB: ProgressReporting {
var isInProgress: Bool { return true }
func reportProgress() {}
func foo() {
/*
I have access to `self.isInProgress` but according to `ProgressReporting` definition,
this class should be `Progressable` which is not, at least not explicitely
*/
_ = self.isInProgress
}
}
I would apreciate if someone can explain me what are the differences 🙂
Thanks in advance.
Speaking about Swift5, there is no difference between the two forms, see Swift 5 Release notes:
Protocols can now constrain their conforming types to those that subclass a given class. Two equivalent forms are supported:
protocol MyView: UIView { /*...*/ }
protocol MyView where Self: UIView { /*...*/ }
Swift 4.2 accepted the second form, but it wasn’t fully implemented and could sometimes crash at compile time or runtime. (SR-5581) (38077232)

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.

Why do we add protocol conformance with extensions?

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"

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.

Can a Swift class be extended multiple times with the same methods?

I am designing a framework that uses protocols and extensions to allow for third-parties to add support for my framework to their existing classes.
I'd also like to include some built-in extensions for known classes like UIView, but I don't want to prevent users from defining their own additional support for the same classes.
My question is is there any way that I can extend the same class twice, and override the same (protocol) method in that class both times, while still having some way to call the other if the first one fails.
Elaboration: I really have three goals here I want to achieve:
I want to allow users of my framework to provide their own extensions for their own (or any) UIView subclasses.
I also need some way to allow general behavior that can apply to all UIViews as a fallback option (i.e. if the specific class extension can't handle it, fall back on the generic UIView extension).
I'd also like to separate out my own implementation, by providing some built-in generic view handling, but in such a way that it doesn't prevent third parties from also defining their own additional generic handling. (If I can't do this, it's not a big deal, the first two parts are the most important.)
I have part 1 working already. The problem is how to get this fallback behavior implemented. If I do it all with extensions, the subclass will override the superclass's implementation of the protocol method. It could call super.method, but I'd like to avoid putting that responsibility on the subclass (in case the author forgets to call super).
I'd like to do this all from the framework code: first, call the object's protocol method. If it returns false, I'd like to somehow call the generic UIView handler.
Now that I'm typing it all out, I'm wondering if I can just use a different method for the generic fallback and be done with it. I just figured it would be elegant if I could do it all with one method.
No! It can't be extended multiple times.
extension Int {
var add: Int {return self + 100} // Line A
}
extension Int {
var add: Int {return self + 105} //Line B
}
Doing so would create a compile time error ( on Line B) indicating: Invalid redeclaration of 'add'
Swift is a static typing language and helps you find these sorts of errors before runtime
In Objective-C you can write this and still not get an error, however the result would be undefined, because you wouldn't know which method gets loaded first during runtime.
Overriding a single protocol method twice in 2 separate extensions wouldn't work, because the protocol method names would collide. Once compiled, they're all just methods on the same class. With that in mind, perhaps put all the protocol methods in their own extension & call them from within the other ones?
The following could be one general option. Could get messy if you decide to keep adding additional extension functionality.
class baseClass {
//stuff
}
extension baseClass: myProtocol {
override func myProtocolMethod(args) -> returnType {
//Repeat this in a separate extension & your method names collide
var status: Bool
//protocol method code sets status as appropriate...
return status = true ? optOne(status) : optTwo(status)
}
func optOne(status:Bool) -> returnType{
//do the 'true' thing
return returnType
}
func optTwo(status:Bool) -> returnType{
//do the 'false' thing
return returnType
}
}
extension baseClass {
var oneExtension = myProtocolMethod(someArg)
}
extension baseClass {
var twoExtension = myProtocolMethod(someArg)
}
I realize this Question is over a year old and the original poster has probably moved on to other things, but I'd like to share an idea anyways and perhaps get some feedback.
You say that you want a method that can be overwritten multiple times. The short answer, like many in this thread have given is no, but the long answer is yes.
We can solve the issue with a bit of generic magic.
class MyView: UIView {
var customizer: MyProtocol<MyView> = Defaults()
func willCallCustomizer() {
customizer.coolMethod(self)
}
}
// Use this class as if it were a protocol
class MyProtocol<T: UIView>: NSObject {
func coolMethod(_ view: T) {}
}
// Class inherits from the "protocol"
class Defaults: MyProtocol<MyView> {
override func coolMethod(_ view: MyView) {
// Some default behavior
}
}
/// on the clients end...
class CustomerCustomizer: MyProtocol<MyView> {
override func coolMethod(_ view: MyView) {
// customized behavior
}
}
So if the client wants to use their own customizer they can just set it, otherwise it will just use the default one.
myViewInstance.customizer = CustomerCustomizer()
The benefit of this approach is that the client can change the customizer object as many times as they want. Because MyProtocol is generic, it may be used for other UIView's as well; thus fulfilling the role of a protocol.