Make enum with return Class inheriting Codable to parse JSON to your model class - ios

I need to make an enum to return class type to using in another function to parse my JSON to model.
Below follows an example of what I wrote.
enum APIType {
case status
var responseType: AnyClass {
switch self {
case .status:
return MyModel.self
}
}
}
But, one error occurred which I assume is happening due to Codable inheritance.
Cannot convert return expression of type 'MyClass.Type' to return type 'AnyClass' (aka 'AnyObject.Type')
Has anyone gone through this challenge? How do I resolve this?

The error is actually quite clear, you are trying to return the class type of an object, but the compiler expects a concrete implementation of any class.
Just replace the return value of responseType to be AnyObject.Type
class MyModel {
}
enum APIType {
case status
var responseType: AnyObject.Type {
switch self {
case .status:
return MyModel.self
}
}
}
print(APIType.status.responseType) // MyModel

Related

Converting Swift enum to Class

I have the following code to implement animation models based on this answer:
public enum AnimationType {
public enum Kind<Value> {
case scalar(Value)
case keyframes([Keyframe<Value>])
}
case position(Kind<Float>)
case scale(Kind<Float>)
case rect(Kind<CGRect>)
case transform(Kind<CGAffineTransform>)
....
....
}
public class Keyframe<T> : Codable, Comparable where T:Codable, T:Interpolatable {
public var time:CMTime
public var property:String
public var value:T
...
...
}
This data model was chosen as I found it type safe for each animation property as it couples data type with the property (for instance, value for property transform can only be CGAffineTransform, the code wouldn't accept anything else). But now I face two troubles:
Directly fetching property value or modifying keyframes is not so easy, one needs to write a big switch statement everytime or atleast if case let statement to fetch the property, which makes code look messy if done at hundreds of places,
Most important, Swift enums are pass by value but I realize I need pass by reference or class based implementation. This is because it would be much easier to modify the underlying object parameters in case of pass by reference. In case of pass by value such as enum, I need to again create new values and pass them to the animation code (which has it's own data model for rendering animation). Reconstructing or updating data structures for animation rendering is a pain and can be avoided with class.
However, I am not sure if there is such a type safe approach to convert such an enum to class, or make enum pass by reference for that matter. Any inputs are welcome.
If you want to keep using enums I think you can make issue 1 a bit easier to deal with if you add an optional property for each associated value in the enum cases.
Something like:
public enum AnimationType {
public enum Kind<Value> {
case scalar(Value)
case keyframes([Keyframe<Value>])
var scalar: Value? {
guard case let .scalar(value) = self else { return nil }
return value
}
var keyframes: [Keyframe<Value>]? {
guard case let .keyframes(keyframes) = self else { return nil }
return keyframes
}
}
case position(Kind<Float>)
case scale(Kind<Float>)
case rect(Kind<CGRect>)
case transform(Kind<CGAffineTransform>)
var position: Kind<Float>? {
guard case let .position(kind) = self else { return nil }
return kind
}
var transform: Kind<CGAffineTransform>? {
guard case let .transform(kind) = self else { return nil }
return kind
}
}
With this you won't need to have the big switch you are mentioning because you directly try to get the associated value you need.
You can also have a look at swift-case-paths which basically adds Keypath support to enum with associated values and removes the need to add this vars boilerplate.

How to return closure in the generic

Now I using Realm to create a singleton, but I faced a problem, if I want to return a closure in the generic, and there are different types (Ex:.Case type return [Case], .Product type return [Product]), but I have no idea to implement this fuction.
Could anyone help me with this problem?Thanks!
DataType:
enum DataType{
case Case
case Product
case Category
case Composition
}
fetchItem fuction:
func fetchItem<T>(type: DataType,complete:#escaping ([T]) -> ()) {
var list:[T]? = []
switch type {
case .Case:
let realm = try! Realm()
let caseResult = realm.objects(Case.self)
caseResult.forEach { (item) in
...
}
complete([])
return
case .Product:
return
case .Category:
return
case .Composition:
return
}
}
Templating a function is the class that you want to get.
Let's take for exemple this function
func showTemplate<T>(myVariable: T) {
print(myVariable)
}
Here, if I want to call the showTemplate function I must do it with the type I want :
showTemplate<String>() # print a string
showTemplate<Int>() # print a int
showTemplate<myClass> # print a myClass
So you are having a problem, but in the wrong way because with templating, you HAVE to know the class before you call the function.
You can for example try to use inheritance and templating your motherClass with your wanted class.
class wantedClass {
var myCaseVariable: Case
var myProductVariable: Product
var myThingsVariable: Things
init() {
}
fillClass<T: Case>() {
// set case
}
// Etc etc
}
Moreover, I don't think that templating is the good solution here, I suggest to look at this : Using a Type Variable in a Generic
I believe you cannot do this for completely different types in one place using only generic type (not any class-holders or so). Maybe you should create separate funcs for each item (fetchCaseItems(), fetchProductItems, etc.). It's much clear to read and every func is responsible only for its own data type.

How do I implement a Swift protocol with a generic constrained type property?

I would like to have a protocol that looks something like this:
protocol ReturnType {
var returnType: ImmutableMappable.Type { get }
}
The part of the enum implementing the protocol:
extension ShimEndPoint: ReturnType {
var returnType: ImmutableMappable.Type {
switch self {
case .deAuthorize(_, _):
return EmptyResponse.self
case .authorize(_, _):
return AuthorizeResponse.self
case .step(_, _, _, _):
return StepResponse.self
}
}
}
EmptyResponse, AuthorizeResponse and StepResponse all implement ImmutableMappable.
Now I would like to use the "returnType" property in a function call:
return Shim.provider
.request(endPoint)
.timeout(7,
scheduler: MainScheduler.asyncInstance)
.retry(3)
.mapObject(endPoint.returnType)
The line mapObject gives me the following compiler error:
"Cannot convert value of type 'ImmutableMappable.Type' to expected argument type 'T.Type'
The function signature of "mapObject" is:
public func mapObject<T : ImmutableMappable>(_ type: T.Type) -> RxSwift.Observable<T>
How do I define and implement the protocol so I can pass in my returnType to the mapObject function?
I found a similar question but unfortunately I could not solve my problem with the help of the answer given:
Returning constrained generics from functions and methods
Personally, I feel like some of your code just doesn't really make sense. Like :
extension ShimEndPoint: ReturnType {
var returnType: ImmutableMappable.Type {
switch self {
case .deAuthorize(_, _):
return EmptyResponse.self
case .authorize(_, _):
return AuthorizeResponse.self
case .step(_, _, _, _):
return StepResponse.self
}
}
}
How can an object determined the type of itself based on itself ? And then return a value type different than itself ?
So what I'm trying to help here is just trying to find a solution of what you are trying to achieve, rather than solve the existing code.
I assume that what you trying to do is determined a type of object to map to depends on the result case at runtime. The enum itself is ImmutableMappable and it has 3 cases : .authorize, .deauthorize and .step.
The function .request will return this type and determined the type to map to, accordingly to the case. However, since the type of object need to be determined at compile time, all the result type EmptyResponse, AuthorizeResponse and StepResponse here must be following a same protocol ( I assume, Response here) and the result will also only return the protocol rather a specific class type.
return Shim.provider
.request(endPoint)
.timeout(7,
scheduler: MainScheduler.asyncInstance)
.retry(3)
.flatMap { result: ImmutableMappable -> Observable<Response> in
return Observable.create{
switch result {
case .authorize:
observer.onNext(AuthorizeResponse())
case .deAuthorize:
//etc
case step:
//etc.
}
}
}
Hope this answer your question !

Swift Type Erasure with Generic Enum and Generic Protocol

I have had to use type erasure in Swift a few times however it always involved a generic protocol. In this case, it involves both a generic enum and and generic protocol and I'm stumped.
Here is my generic enum and generic protocol with the necessary extension:
enum UIState<T> {
case Loading
case Success([T])
case Failure(ErrorType)
}
protocol ModelsDelegate: class {
associatedtype Model
var state: UIState<[Model]> { get set }
}
extension ModelsDelegate {
func getNewState(state: UIState<[Model]>) -> UIState<[Model]> {
return state
}
func setNewState(models: UIState<[Model]>) {
state = models
}
}
And here is my type erased generic class:
class AnyModelsDelegate<T>: ModelsDelegate {
var state: UIState<[T]> {
get { return _getNewState(UIState<[T]>) } // Error #1
set { _setNewState(newValue) }
}
private let _getNewState: ((UIState<[T]>) -> UIState<[T]>)
private let _setNewState: (UIState<[T]> -> Void)
required init<U: ModelsDelegate where U.Model == T>(_ models: U) {
_getNewState = models.getNewState
_setNewState = models.setNewState
}
}
I'm getting the following errors (they are marked in the code sample):
Error #1:
Cannot convert value of type '(UIState<[T]>).Type' (aka 'UIState<Array<T>>.Type') to expected argument type 'UIState<[_]>' (aka 'UIState<Array<_>>')
I have been working on this for awhile and there have been quite a few variations on this code that "almost worked". The error always has to do with the getter.
The problem that causes this error, as #dan has pointed out, is that on this line you're trying to pass a type as an argument, instead of an instance of that type:
get { return _getNewState(UIState<[T]>) }
However, I would question your use of an argument to this function in the first place, surely a getting function should have no argument at all? In this case you'll simply want your _getNewState function to have the signature () -> UIState<[T]>, and call it like so:
get { return _getNewState() }
Also, if your getNewState and setNewState(_:) functions in your protocol extension only exist in order to forward the getting and setting of your state property to the type-erasure – you can simplify your code by getting rid of them entirely and use closure expressions in the type-erasure's init instead:
_getNewState = { models.state }
_setNewState = { models.state = $0 }
(These work by capturing a reference to the models argument, for more info see Closures: Capturing Values)
Finally, I suspect that you mean to refer to UIState<T> rather than UIState<[T]> throughout your code, as T in this case refers to an element in the array that your .Success case has as an associated value (unless you want a 2D array here).
All in all, with the above proposed changes, you'll want your code to look something like this:
enum UIState<T> {
case Loading
case Success([T])
case Failure(ErrorType)
}
protocol ModelsDelegate: class {
associatedtype Model
var state: UIState<Model> { get set }
}
class AnyModelsDelegate<T>: ModelsDelegate {
var state: UIState<T> {
get { return _getNewState() }
set { _setNewState(newValue) }
}
private let _getNewState: () -> UIState<T>
private let _setNewState: (UIState<T>) -> Void
required init<U: ModelsDelegate where U.Model == T>(_ models: U) {
_getNewState = { models.state }
_setNewState = { models.state = $0 }
}
}

Cannot convert return expression of generic protocol's function type implementation

I'd like to use swift generics in a way described below:
class ResponseContainer {
}
protocol DisplayManageable {
func getModel<ModelType: ResponseContainer>() -> ModelType?
}
class DisplayBaseManager<ObtainedModelType: ResponseContainer>: NSObject, DisplayManageable {
var modelObtained: ObtainedModelType? = nil
func getModel<ObtainedModelType>() -> ObtainedModelType? {
return modelObtained
}
}
But I have a problem with this code, more precisely there is a problem in this line:
return modelObtained
And I'm getting the error:
Cannot convert return expression of type 'ObtainedModelType?' to
return type 'ObtainedModelType?'
And now my simple question, why can't I do that? What's wrong with that?
Generics in protocol's function and in class definitions are the same. Everything looks fine in my opinion and logically is ok, so why cannot I do so?
In
func getModel<ObtainedModelType>() -> ObtainedModelType? { ... }
ObtainedModelType introduces a local generic placeholder, and that
hides the ObtainedModelType from the class definition
class DisplayBaseManager<ObtainedModelType: ResponseContainer>
This causes the strange looking error message
Cannot convert return expression of type 'ObtainedModelType?' to return type 'ObtainedModelType?'
because return modelObtained has the generic type ObtainedModelType? from the
class definition, but the expected return type is ObtainedModelType?
from the method definition.
What you probably want is a protocol with an associated type
protocol DisplayManageable {
associatedtype ModelType: ResponseContainer
func getModel() -> ModelType?
}
and a class adopting this protocol with ModelType == ObtainedModelType:
class DisplayBaseManager<ObtainedModelType: ResponseContainer>: NSObject, DisplayManageable {
var modelObtained: ObtainedModelType? = nil
func getModel() -> ObtainedModelType? {
return modelObtained
}
}
Łukasz, I don't now why it doesn't compile but I found the way to compile it. Just change the return statement:
return modelObtained as? ObtainedModelType
But I'm still waiting for someone to explain the reason for error in the original code.

Resources