How to call a static method on a class Template method? - swift

I try to call a class method on a generic T: BaseModel where T can be a subclass of BaseModel.
For example Car.
In the case T should be Car, I want my class method to be called on the Car class.
However, It always ends up calling the BaseModel class method instead.
class func parse<T: BaseModel>(json: JSON, context: NSManagedObjectContext) throws -> T? {
return T.classParseMethod(json: json) //This never calls the Car.classParseMethod()
}
where
let carObject = parse(json:json, context:context) as? Car
Any help?

The casting is done after the function call so the generic constraint resolves to T = BaseModel. You want the function to know of the type so it can properly resolve the generic constraint:
func parse<T: BaseModel>(_ str: String) -> T? {
print(T.Type.self) // should print like: Car.Type
return T.parse(str) as? T
}
// Make the desired type known to swift
let car: Car? = parse("My Car Format String")

One solution that seems to work is:
to add
func myFunc<T: BaseModel>(_ type: T.Type,..) -> T? {
type.aClassFunc()
{
If I call the following, it works.
if let obj = myFunc(Car.self, ...) {
// obj will be of type Car
}
It seems really too much just to achieve this but there might be an underlying reason for it.

Related

Stored type to function parameter

I face the following issue,
I have a swift function that takes a T.Type as parameter
public static func register<T:Decodable>(_ type:T.Type, clousure:#escaping()->NSDictionary){
public static func make<T:Decodable>(_ type:T.Type, _ overload:NSDictionary? = nil) -> T?{
I register it to a dictionary of type
static var factories = [String: () -> NSDictionary]()
This way I can create a new object from a dictionary by just decoding it
when calling it this way Factory.make(MyType.self)
However, I want it to be a bit more powerful and be able to do factories from a dictionary containing another class
Factory.make(MyType.self) {[
"name": A random name,
"subObject": SubOject.self
}]
And here is when I face the problem, to detect this suboject and call make to it
finalDict.allKeys.forEach { key in
if let className = finalDict[key] as? AnyClass {
print(className)
//finalDict[key] = Factory.make(className.self)
//finalDict[key] = Factory.make(className)
}
}
I can't do that, I've tried casting to AnyClass, AnyObject.Type... but them all make the compiler fail,
Do you know how to fix this?
Thank you!

Can not check equality of values of type T: Equatable inside a generic

I'm currently trying out with some basic data structures like LinkedList. I defined a ListNode class of generics values, like this:
class ListNode<T> {
var nodeContent: T
var nextNode: ListNode<T>? = nil
init() {
// details omitted here
}
And then a linked list. I want to implement the contains() method, so I have sth like this:
func contains<T>(_ item: T) -> Bool {
var currNode = self.head
while (currNode != nil) {
if currNode?.nodeContent == item {
return true
}
currNode = currNode?.nextNode
}
return false
}
Then it's giving me error saying that '==' cannot applied to T and T types. I then looked through the language guide and changed ListNode class and LinkedList struct to this:
class ListNode<T: Equatable>{}
struct LinkedList<T: Equatable>{}
But it's not working, so I added 'Equatable' to func itself:
func contains<T: Equatable>(_ item: T) -> Bool
Still fails. I tried pasting the sample function from the language guide inside,
func findIndex<T: Equatable>(of valueToFind: T, in array:[T]) -> Int? {
for (index, value) in array.enumerated() {
if value == valueToFind {
return index
}
}
return nil
}
No error occurs. May I know why it's like this? I tried searching, but all suggested answers like this doesn't clear my doubts. Thanks in advance!
You just don't need to make the contains method generic (twice). It's inside of your already generic class and knows about T type. It's right to require T: Equatable in the type declaration.
findIndex(of:in:) works as is, because it's not a method, but rather a standalone generic function.

Check if the generic type is a function type in Swift

I have defined a generic class as follows
class A<T:Any>{
var value:T?
}
I would like to know how I could limit T to be of a function type and can write code like value() in Class A.
let a = A<()->()>()
I was having a similar problem, I ended up solving it like so:
First I defined a generic type representing a function which accepts a single parameter, and return value:
typealias Monad<A, R> = (A) -> (R)
I then defined my class to take a generic type parameter for the input type. In my case, every function passed was going to return void so I didn't need two type parameters.
class HoldsMyCallback<A> {
let callback: Monad<A, Void>
init(callback: #escaping Monad<A, Void>) {
self.callback = callback
}
}
...
let funcKoozie = HoldsMyCallback<Int> {
print("keep my \($0) function cold")
}
funcKoozie.callback(1)
Referring to Apple's Documentation:
Generic code enables you to write flexible, reusable functions and
types that can work with any type, subject to requirements that you
define.
This is the main purpose of using Generics.
In your case, probably, this is the not right way of how to use them. You might want to make more simple:
typealias funcion = ()->()
class A {
private var value:funcion?
init(value: #escaping funcion) {
self.value = value
}
func doSomething() {
print("do something 01")
if let iplementedValue = value {
iplementedValue()
}
print("do something 02")
}
}
Instantiation:
let aObject = A(value: {
print("I want to this in the middle of my \"doSomething\"")
})
aObject.doSomething()
The output should looks like:
do somthing 01
I want to this in the middle of my "doSomething"
do somthing 02
Hope that helped.

How to call a static method on a base class from a generic class<T>?

I'm trying to call a static method in a base class from a generic subclass. See simplified playground code below.
Calling the non-static 'dump' function works.
The similar static call fails. Various attempts to typecast the array also fail.
In the full production code, "ClassA" is in a 3rd-party module and can't be changed. It can be further subclassed and extended.
Does Swift offer some magical typecast to have ClassT call ClassA.dump() directly?
class ClassT<T> {
var dict=[String:T]()
func add(key:String, obj:T) {
dict[key]=obj
let arr=Array(dict.values)
dump(arr) // works -> but not as expected, see comment below !!!
ClassA.dump(arr) // error: cannot convert value of type 'Array<T>' to expected argument type '[ClassA]'
ClassA.dump(arr as! [ClassA]) // error: cannot convert value of type 'Array<T>' to type '[ClassA]' in coercion
ClassA.dump(arr as! [AnyObject]) // error: 'AnyObject' is not a subtype of 'T'
ClassA.dump(arr as! [Any]) // error: 'Any' is not a subtype of 'T'
}
}
class ClassA {
func dump(arr:[ClassA]) {
ClassA.dump(arr)
}
static func dump(arr:[ClassA]) {
print(arr)
}
}
class ClassB:ClassA {
static let o=ClassT<ClassA>()
func test() {
ClassB.o.add("Elem1", obj:self)
}
}
You have to add a constraint to specify that T derives from ClassA.
class ClassT<T: ClassA> {
var dict = [String : T]()
func add(key: String, obj: T) {
dict[key] = obj
let arr = Array(dict.values) //probably unecessary
dump(arr) // works
ClassA.dump(arr)
}
//...
Without it, the compiler has no way to enforce that all conforming types T will be castable to ClassA.

Call Class Methods From Protocol As Parameter

I want to be able to pass a class (not an initialized object) of a certain protocol type to a method, then call the class functions of that class in the method. Code below.
I am using Swift and have an protocol defined like this
//Protocol for any object to be used with an FAUAPIConnection
protocol FAUAPIModel{
//Used to parse the object from a given dictionary to an object
class func parseFromJSON(JSON:AnyObject) -> Self
//Required default init
init()
}
What I would like to do is have a method like this
func getSomeParsingDone<T:FAUAPIModel>(model:T.Type? = nil, getPath:path, callingObj:CallingClass) -> Void
{
//GetIt is inconsequential, just logic to get an object from a certain path
var returnObj:AnyObject = GetIt.get(path)
if(model != nil){
returnObj = model!.parseFromJSON() <<<<<< Type 'T' does not conform to protocol 'AnyObject'
}
callingObj.done(returnObj)
}
Object that implements the protocol
import Foundation
class MyObj: FAUAPIModel{
var neededVal:String
var nonneededVal:String
required convenience init(){
self.init(neededVal:"VALUE")
}
init(neededVal:String, nonneededVal:String = ""){
self.neededVal = neededVal
self.nonneededVal = nonneededVal
}
class func parseFromJSON(JSON:AnyObject) -> WGMPart
{
return WGMPart() <<<<<<<< Method 'parseFromJSON' in non-final class 'WGMPart' must return 'Self' to conform to protocol 'FAUAPIModel'
}
}
However, I keep getting two errors. I have indicated these above with '<<<<<<<<<<<<'
compile error.
Lots of little things to consider here, but let's get to the heart of your question. The signature you want looks like this:
func getSomeParsingDone<T:FAUAPIModel>(model:T.Type, path:String) -> T?
I'm making the return optional beause there are a lot of things that could fail here, and you really shouldn't turn all of those into crashes.
I'd recommend your protocol look like this:
protocol FAUAPIModel {
class func parseFromJSON(JSON:AnyObject) -> Self
}
That way, you're promising that your return your own class, not just anything that is parseable. That does tend to mean that you need to make your classes final. If you don't want them to be final, you'll need to promise some init method in order to construct it. See Protocol func returning Self for more details on how to deal with that if you need it.
So putting it together, it might look something like this in practice:
protocol FAUAPIModel {
class func parseFromJSON(JSON:AnyObject) -> Self
}
func createObjectOfClass<T: FAUAPIModel>(model: T.Type, path: String) -> T? {
if let json: AnyObject = GetJSON(path) {
return model.parseFromJSON(json)
}
return nil
}
// Bogus JSON reader
func GetJSON(path: String) -> AnyObject? {
let json: AnyObject? = NSJSONSerialization.JSONObjectWithData(path.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: true)!, options: NSJSONReadingOptions(0), error: nil)
return json
}
// Bogus model class that returns trivial version of itself
final class Something: FAUAPIModel {
class func parseFromJSON(JSON:AnyObject) -> Something {
return Something()
}
}
// Using it
let something = createObjectOfClass(Something.self, "/path/to/file")
I just want to note that the answer to your exact question would be to declare your function like this:
func getSomeParsingDone(model:FAUAPIModel.Type? = nil, getPath:path) -> FAUAPIModel