Jay Zon Jay Zon - 19 days ago 10
iOS Question

How to instantiate an Object inside a Base class in Swift 3

I have a ModelBase class and I am subclassing from it with a few classes (i.e Task, Milestone, etc). I want to create a static method named "all" that will fetch all the models (let's say an array) but I want the array to be of of type [Task] not [ModelBase]. Though I don't want to write that method for each subclass if possible.

class Task: ModelBase {
override class var tableName : String {return "Task"}


}

Then I can do:

Task.all({ (tasks:[Task]) in
// do stuff with tasks
});


So far I have been using type(of: self) to access class level variables inside of non static / class methods.

However, I would like to have a static method that can fetch models from the API but I can't figure out how to reference the current class (i.e Task in this case)

Please let me know if what I am trying to do makes sense / is possible. Here is my sample code fetching from parse.

class ModelBase: NSObject {

// THIS WORKS FINE --->
class var tableName : String {return "ModelBase"}

init(_ _dictionary: [String: Any]) {

self.dictionary = _dictionary
_parseObject = PFObject(className: type(of: self).tableName)
}

// THIS IS WHAT FAILS -------------->
class func all(_ success: @escaping ([ModelBase]) ->(), failure: @escaping (Error) -> ()){
var models = [ModelBase]()
let questsQuery = PFQuery(className: ModelBase.tableName)

questsQuery.findObjectsInBackground {
(objects: [PFObject]?, error: Error?) -> Void in

if let error = error {
failure(error)
} else {
if let objects = objects {
for object in objects {
models.append( ModelBase(parseObject: object as PFObject))
}
success(models)
} else {
success([])
}
}
}
}

}

Answer

If I understand correctly, you want this code to by polymorphous over any subclass of ModelBase. For this I would suggest using generics.

class func all<T: ModelBase>(_ success: @escaping ([T]) ->(), failure: @escaping (Error) -> ()) {
    let questsQuery = PFQuery(className: T.tableName)

    questsQuery.findObjectsInBackground {
        (objects: [PFObject]?, error: Error?) -> Void in

        if let error = error {
            failure(error)
            return
        } 

        guard let objects = objects else {
            success([])
            return
        }

        let models = objects.map{ T(parseObject: $0 as PFObject) }
        success(models)
    }
}
Comments