Swift protocol to only implemented by specific classes - swift

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.

Related

What's the point of conforming to an empty protocol in Swift

I'm just working on a codebase where the most classes conform to an empty protocol. Is there any point of doing so? Actually conforming that protocol does nothing.
Edit as reaction to #vacawama's helpful comment : the protocol is only used once
import Foundation
protocol myUrlRequestConfig {}
extension myUrlRequest: myUrlRequestConfig {
public static func configGetAppConfig() -> URLRequest {
let request = ....
return request
}
}
An empty protocol can be useful if you want to create an easy way to add static functions or variables to several different classes. Of course, this only makes sense if the static functionality is the same for all classes conforming to the protocol.
Here is an example: I have a protocol sizeable. Every class that conforms to Sizeable is extended with the static variable stride and size.
protocol Sizeable { }
extension Sizeable {
static var size: Int {
return MemoryLayout<Self>.size
}
static var stride: Int {
return MemoryLayout<Self>.stride
}
}
class Foo: Sizeable {}
class Baa: Sizeable {}
Foo.size
Baa.size
Our app has three perfectly legitimate uses for an empty protocol:
The protocol has an extension with method definitions. The implementation in the extension is automatically injected into any type that adopts the protocol.
The protocol has other protocols that adopt it. This allows multiple protocols to be unified under a single head.
The protocol marks the adopter as wanting some other type to behave in a certain way. Code can always is whether an object is ThisEmptyProtocol and if it is, can behave differently than if it isn't.

Swift Generics - Attempting to make a generic protocol concrete fails when attempting to use specialised sub-protocol as variable

I want to know why my SomeResourceRepository is still generic, even though it is only defined in one case only, which is when I set ResourceType = SomeResource, which XCode formats as below with the where clause. Code below which shows the exact setup I'm trying to achieve, written in a Playground.
I am trying to define a generic protocol for any given ResourceType such that the ResourceTypeRepository protocol then automatically requires the same set of functions, without having to copy-paste most of GenericRepository only to manually fill in the ResourceType for each Repository I make. The reason I need this as a protocol is because I want to be able to mock this for testing purposes later. So I'll provide an implementation of said protocol somewhere else in the actual app.
My interpretation of the code below is that it should work, because both SomeResourceLocalRepository and SomeResourceRemoteRepository are concrete, as I have eliminated the associated type by defining them "on top of" SomeResourceRepository, which is only defined where ResourceType == SomeResource.
import Foundation
struct SomeResource: Identifiable {
let id: String
let name: String
}
struct WhateverResource: Identifiable {
let id: UUID
let count: UInt
}
protocol GenericRepository: class where ResourceType: Identifiable {
associatedtype ResourceType
func index() -> Array<ResourceType>
func show(id: ResourceType.ID) -> ResourceType?
func update(resource: ResourceType)
func delete(id: ResourceType.ID)
}
protocol SomeResourceRepository: GenericRepository where ResourceType == SomeResource {}
protocol SomeResourceLocalRepository: SomeResourceRepository {}
protocol SomeResourceRemoteRepository: SomeResourceRepository {}
class SomeResourceLocalRepositoryImplementation: SomeResourceLocalRepository {
func index() -> Array<SomeResource> {
return []
}
func show(id: String) -> SomeResource? {
return nil
}
func update(resource: SomeResource) {
}
func delete(id: String) {
}
}
class SomeResourceService {
let local: SomeResourceLocalRepository
init(local: SomeResourceLocalRepository) {
self.local = local
}
}
// Some Dip code somewhere
// container.register(.singleton) { SomeResourceLocalRepositoryImplementation() as SomeResourceLocalRepository }
Errors:
error: Generic Protocols.xcplaygroundpage:45:16: error: protocol 'SomeResourceLocalRepository' can only be used as a generic constraint because it has Self or associated type requirements
let local: SomeResourceLocalRepository
^
error: Generic Protocols.xcplaygroundpage:47:17: error: protocol 'SomeResourceLocalRepository' can only be used as a generic constraint because it has Self or associated type requirements
init(local: SomeResourceLocalRepository) {
I will probably have to find another way to accomplish this, but it is tedious and quite annoying as we will produce a lot of duplicate code, and when we decide to change the API of our repositories, we will have to manually change it for all the protocols as we don't follow a generic "parent" protocol in this work-around.
I have read How to pass protocol with associated type as parameter in Swift and the related question found in an answer to this question, as well as Specializing Generic Protocol and others.
I feel like this should work, but it does not. The end goal is a concrete protocol that can be used for dependency injection, e.g. container.register(.singleton) { ProtocolImplementation() as Protocol } as per Dip - A simple Dependency Injection Container, BUT without copy-pasting when the protocol's interface clearly can be made generic, like in the above.
As swift provides a way to declare generic protocols (using associatedtype keyword) it's impossible to declare a generic protocol property without another generic constraint. So the easiest way would be to declare resource service class generic - class SomeResourceService<Repository: GenericRepository>.
But this solution has a big downside - you need to constraint generics everywhere this service would be involved.
You can drop generic constraint from the service declaration by declaring local as a concrete generic type. But how to transit from generic protocol to the concrete generic class?
There's a way. You can define a wrapper generic class which conforms to GenericRepository. It does not really implements its methods but rather passes to an object (which is real GenericRepository) it wraps.
class AnyGenericRepository<ResourceType: Identifiable>: GenericRepository {
// any usage of GenericRepository must be a generic argument
init<Base: GenericRepository>(_ base: Base) where Base.ResourceType == ResourceType {
// we cannot store Base as a class property without putting it in generics list
// but we can store closures instead
indexGetter = { base.index() }
// and same for other methods or properties
// if GenericRepository contained a generic method it would be impossible to make
}
private let indexGetter: () -> [ResourceType] {
indexGetter()
}
// ... other GenericRepository methods
}
So now we have a concrete type which wraps real GenericRepository. You can adopt it in SomeResourceService without any alarm.
class SomeResourceService {
let local: AnyGenericRepository<SomeResource>
}

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"

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.

How to call static methods on a protocol if they are defined in a protocol extension?

protocol Car {
static func foo()
}
struct Truck : Car {
}
extension Car {
static func foo() {
print("bar")
}
}
Car.foo() // Does not work
// Error: Car does not have a member named foo
Truck.foo() // Works
Xcode autocompletes the Car.foo() correctly, so what i'm asking is if its a bug that it doesn't compile (says it does not have a member named foo()). Could you call static methods directly on the protocol if they are defined in a protocol extension?
Apple doc
Protocols do not actually implement any functionality themselves.
Nonetheless, any protocol you create will become a fully-fledged type
for use in your code.
Therefore, you cannot call static methods directly of protocol.
No, the error message isn't good, but it's telling you the correct thing.
Think of it this way, you can't have
protocol Car {
static func foo() {
print("bar")
}
}
This compiles with the error "Protocol methods may not have bodies".
Protocol extensions don't add abilities to protocols which don't exist.