Xcode Warning: Non-final class 'CustomMedication' cannot safely conform to protocol 'CustomComponent', which requires that 'Self.C.CC' is exactly - swift

Context
I am currently working with Protocols and AssociatedTypes and encountered the following new Xcode Warning I don't really understand.
Non-final class 'SomeCustomComponent' cannot safely conform to protocol 'CustomComponent', which requires that 'Self.C.CC' is exactly equal to 'Self'; this is an error in Swift 6
Code
protocol Component {
associatedtype CC: CustomComponent where CC.C == Self
var customComponent: CC { get }
}
protocol CustomComponent {
associatedtype C: Component where C.CC == Self
var component: C { get }
}
enum SomeComponent: Component {
var customComponent: { ... }
}
// Please note, that SomeCustomComponent is an NSManagedObject conforming to CustomComponent.
extension SomeCustomComponent: CustomComponent { // I get the Xcode Warning in this Line.
var component: C { ... }
}
Question
How can I handle this Xcode Warning? Is it possible to mark an NSManagedObject as final? And how do I do it since it is defined in the background?

You can mark an NSManagedObject subclass as final but this of course requires that you manage the code for the subclass yourself, that is set Codegen to Manual for this entity in your core data model.
Regarding the final requirement, this is because if you would create a subclass the mapping between the two protocols might break.
Consider if you create a subclass of SomeCustomComponent,
class SubCustomComponent: SomeCustomComponent {}
with no other changes that concern the protocols. Then the component property of the subclass would point to the enum SomeComponent but the enum would not point back to the new class SubCustomComponent but to its superclass.
So if you would use this for some kind of conversion or mapping in both directions your would go from SubCustomComponent to SomeComponent and back to SomeCustomComponent which is surely a bug.

Related

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>
}

Swift protocol conformance requirements for subtypes [duplicate]

This question already has answers here:
Why can't a get-only property requirement in a protocol be satisfied by a property which conforms?
(3 answers)
Closed 5 years ago.
(if someone can suggest a better title, please do)
The following code does not compile with an error Type 'ObserverClass' does not conform to protocol 'Observer', and compiler suggests a fix by declaring var object: ObservedObject.
class ObservedObject {}
class ObservedObjectSubclass: ObservedObject {}
protocol Observer {
var object: ObservedObject { get }
}
class ObserverClass: Observer { // Type 'ObserverClass' does not conform to protocol 'Observer'
// suggested:
// var object: ObservedObject
var object: ObservedObjectSubclass = ObservedObjectSubclass()
}
The way i see it - ObservedObjectSubclass is ObservedObject, and so object property is guaranteed to be of type ObservedObject as required by the protocol.
(The same is true, if using protocol conformance instead of subclassing - below)
protocol ObservedObjectProtocol {}
protocol Observer {
var object: ObservedObjectProtocol { get }
}
class ObservedObject: ObservedObjectProtocol {}
class ObserverClass: Observer { // same error
var object: ObservedObject = ObservedObject()
}
Why is compiler unhappy? Is it current limitation, or the compiler is actually right and there is some logical constraint?
When you define a variable in a protocol and assign a type to it, that is going to be a concrete type, so you cannot change it to a subclass of that type when conforming to the protocol. The type of the variable declared in the conforming class must be the same type as declared in the protocol, it cannot be a covariant (inheritance related) type.
You can fix the second error by creating an associatedType for your Observer protocol, which inherits from ObserverObject then you can define object to be of the same type as your associated type. Then you can make your ObserverClass have a property object of type ObservedObjectSubclass.
class ObservedObject {}
class ObservedObjectSubclass: ObservedObject {}
protocol Observer {
associatedtype ObjectSubclass: ObservedObject
var object:ObjectSubclass { get }
}
class ObserverClass: Observer {
var object = ObservedObjectSubclass()
}

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.

Define property that must be a subclass AND conform to protocol

In Swift 2.0, how can I do the equivalent of #property (nonatomic, strong) NSManagedObject*<SomeProtocol> model?
Basically, I’m trying to define a property on my class that must both be a subclass of NSManagedObject AND conform to SomeProtocol (I will be calling methods defined by both).
I saw this: https://stackoverflow.com/a/25826948/363789, but I'm not sure how I can apply this syntax to property definition...
Swift 4
This is now possible in Swift 4 using the following syntax:
var myObject: NSManagedObject & SomeProtocol
Unfortunately Swift doesn't support such type composition yet.
Three reasonable good solutions as workaround (the third one is probably the best):
1.
You can make another type with has those properties and all types have to inherit from it in order to be used as model.
class SomeManagedObject: NSManagedObject, SomeProtocol {
// conforming to protocol
func someMethod()
}
// type declaration
var model: SomeManagedObject
2.
A more static way to solve this problem is to use generics:
class Aclass<T: NSManagedObject where T: SomeProtocol > {
var model: T
}
Note: You don't have to care about another type which has to be the superclass but this solution is not as dynamic and abstract as the one before.
3.
You could also make your own protocol and make NSManagedObject conform though an extension:
protocol ManagedProtocol {
// if you want to access some methods/properties directly from the type
func method()
var variable: Int { get }
// otherwise call all methods/properties through "managedObject"
// this property also reduces casting if you want to have the object itself
var managedObject: NSManagedObject { get }
}
extension NSManagedObject: ManagedProtocol {
var managedObject: NSManagedObject { return self }
}
Now the type is abstract and can be written as:
var model: protocol<ManagedProtocol, SomeProtocol>

Swift: Property conforming to a specific class and in the same time to multiple protocols

In Objective-C, it's possible to write something like that:
#property(retain) UIView<Protocol1, Protocol2, ...> *myView;
But how can I write this code in swift?
I already know how to make a property conform to many protocols, but it does not work by using the inheritance:
var myView: ??? protocol<Protocol1, Protocol2, ...>
Edit:
I use many UIView subtypes like UIImageView, UILabel or others, and I need to use some of the UIView properties plus some methods defined in the protocols. In the worst case I could create a UIViewProtocol with the needed properties, but I would know if it is possible in Swift to declare a property/variable with a type and some protocol to conform with.
You can do this with a generic class using a where clause:
A where clause enables you to require that an associated type conforms
to a certain protocol, and/or that certain type parameters and
associated types be the same.
To use it, make the class your property is defined in a generic class with a type constraint to check if the type parameter for your property matches your desired base class and protocols.
For your specific example, it could look something like this:
class MyViewController<T where T: UIView, T: Protocol1, T: Protocol2>: UIViewController {
var myView: T
// ...
}
In Swift 4 it's finally possible. You can declare variable of some class conforming to protocol at the same time, like this:
class ClassA {
var someVar: String?
}
protocol ProtocolA {}
class ClassB {
var someOptional: (ClassA & ProtocolA)? // here is optional value
var some: ClassA & ProtocolA // here is non-optional value; need to provide init though :)
}
One and probably a bit ugly one of the ways to do that, is to create a wrapper protocol for UIView:
protocol UIViewRef {
var instance: UIView { get }
}
Now it is possible to create a protocol which implements Protocol1, Protocol2 and UIViewRef, which is going to be used to get the UIView itself:
protocol MyUIViewProtocol: UIViewRef, Protocol1, Protocol2 { }
And last step will be implementing UIViewRef protocols for your UIViews, which, in you case, as I understand, already implement Protocol1 and Protocol2:
// SomeOfMyViews already implements Protocol1 and Protocol2
extension SomeOfMyUIViews: MyUIViewProtocol {
var instance: UIView { return self }
}
As the result we have MyUIViewProtocol, implementers of which hold a reference to a UIView and each of them implement
Protocol1 and Protocol2. One caveat though - to get the UIView itself, we need to ask it's reference from instance
property. For example
// Lets say we're somewhere in a UIViewController
var views: [SomeOfMyUIView] = // Get list of my views
views.forEach { self.view.addSubview($0.instance) }