简体   繁体   English

如何在Swift4上使用通用T.Type类时调用正确的构造函数?

[英]How to call the correct constructor when using generic T.Type class on Swift4?

I have a database with some tables, each table represents a object of my project. 我有一个包含一些表的数据库,每个表代表我项目的一个对象。 I want write a generic function to read, by SQL, a table and create a object with the records readed. 我想写一个通用函数来通过SQL读取一个表并创建一个带有记录的对象。 So, the parameters of my function are: Table Name and Object Type. 所以,我的函数的参数是:表名和对象类型。 The code below is my func to do this. 下面的代码是我执行此操作的函数。 In the end of func, I tries call what I would like to do, but with a especific object, that's don't the I want. 在func的最后,我尝试调用我想做的事情,但是有一个特定的对象,那不是我想要的。

func readAll<T>(objeto: String, typeClass: T.Type) -> [T] {
    var ret : [T] = []

    // STATEMENT DATA
    let queryString = "SELECT * FROM \(objeto);"
    var queryStatement: OpaquePointer? = nil

    // STATEMENT DATA TYPE
    let queryString2 = "PRAGMA table_info(\(objeto));"
    var queryStatement2: OpaquePointer? = nil

    // 1
    if sqlite3_prepare_v2(db,queryString,-1,&queryStatement,nil) != SQLITE_OK {
        print("Error to compile readAll \(objeto) 1")
        return ret
    }

    if sqlite3_prepare_v2(db,queryString2,-1,&queryStatement2,nil) != SQLITE_OK {
        print("Error to compile readAll \(objeto) 2")
        return ret
    }

    var listNameColumns : [String] = []

    while( sqlite3_step(queryStatement2) == SQLITE_ROW ) {
        listNameColumns.append( String(cString: sqlite3_column_text(queryStatement2, 2)!) )
    }

    // 2
    while ( sqlite3_step(queryStatement) == SQLITE_ROW ) {
        var dict: [String:Any] = [:]

        for i in 0...listNameColumns.count-1 {
            let nameColumn = String(cString: sqlite3_column_name(queryStatement,Int32(i))!)
            switch (sqlite3_column_type(queryStatement, Int32(i))) {

            case SQLITE_TEXT:
                dict[nameColumn] = String(cString: sqlite3_column_text(queryStatement, Int32(i))!)
                break

            case SQLITE_INTEGER:
                dict[nameColumn] = sqlite3_column_int(queryStatement, Int32(i))
                break

            case SQLITE_FLOAT:
                dict[nameColumn] = sqlite3_column_double(queryStatement, Int32(i))
                break

            default:
                print("Tipo desconhecido.")
                break
            }
        }

        ret.append(ResPartner(dict: dict)) <------ HERE IS MY QUESTION!
    }

    // 3
    sqlite3_finalize(queryStatement2)
    sqlite3_finalize(queryStatement)

    return ret
}

Here are two objects, They are a bit different, but the builder works the same and the fields as well. 这里有两个对象,它们有点不同,但构建器的工作方式和字段相同。

class ResPartner {

    static let fieldsResPartner : [String] = ["id","company_type_enum_for_customer","name","contact_address","customer_account_number","customer_group_id","segment_id","subsegment_id","economic_group_id","street","category_id","type_stablishment_id","final_user","final_taxpayer","cnpj_cpf","inscr_est","ccm","cnae","phone","phone_extension","mobile","fax","email","email_extra","website","lang"]

    var attributes : [String:Any] = [:]

    init(dict : [String:Any]) {
        for k in dict.keys {
            if(ResPartner.fieldsResPartner.contains(k)) {
                attributes[k] = dict[k]
            }
        }
    }

    func toString() {
        for k in attributes.keys{
            print("\(k) - \(attributes[k]!)")
        }
    }
}

class Product {

       static let fieldsProducts : [String] =  ["id","name","default_code","display_name","categ_id","company_ax_id","destination_type","fiscal_class_code","multiple","taxes_id","uom_id","uom_po_id","__last_update","active","create_date","create_uid","currency_id","invoice_police","item_ids","list_price","price","pricelist_id","type"]

    public var default_code: String!
    public var display_name: String!
    public var id: Int!
    public var name: String!
    public var destination_type: String!
    public var company_ax_id: Int!
    public var categ_id: Int!
    public var fiscal_class_code: String!
    public var taxes_id: Int!
    public var uom_id: Int!
    public var uom_po_id: Int!
    public var multiple: Int!
    public var last_update: String!
    public var active: Bool!
    public var create_date: String!
    public var create_uid: Int!
    public var currency_id: Int!
    public var invoice_police: String!
    public var item_ids: [Int]!
    public var list_price: String!
    public var price: Float!
    public var pricelist_id: Int!
    public var type: String!

    init() {

    }

    init( dict : [String:Any] ) {
        self.default_code = dict["default_code"] as! String
        self.display_name = dict["display_name"] as! String
        self.id = dict["id"] as! Int
        self.name = dict["name"] as! String
        self.destination_type = dict["destination_type"] as! String
        self.company_ax_id = dict["company_ax_id"] as! Int
        self.categ_id = dict["categ_id"] as! Int
        self.fiscal_class_code = dict["fiscal_class_code"] as! String
        self.taxes_id = dict["taxes_id"] as! Int
        self.uom_id = dict["uom_id"] as! Int
        self.uom_po_id = dict["uom_po_id"] as! Int
        self.multiple = dict["multiple"] as! Int
        self.last_update = dict["last_update"] as! String
        self.active = dict["active"] as! Bool
        self.create_date = dict["create_date"] as! String
        self.create_uid = dict["create_uid"] as! Int
        self.currency_id = dict["currency_id"] as! Int
        self.invoice_police = dict["invoice_police"] as! String
        self.item_ids = dict["item_ids"] as! [Int]
        self.list_price = dict["list_price"] as! String
        self.price = dict["price"] as! Float
        self.pricelist_id = dict["pricelist_id"] as! Int
        self.type = dict["type"] as! String
    }
}

So, my question is, How I call the constructor of T.Type class passed by parameter? 所以,我的问题是,我如何调用由参数传递的T.Type类的构造函数? I did read about protocols, extensions, other posts, but not solves my problem. 我确实读过有关协议,扩展,其他帖子,但没有解决我的问题。

You can constrain your generic with protocol: 您可以使用协议约束您的泛型:

  1. Define a protocol for initializing with a dictionary: 定义用字典初始化的协议:

     protocol DictionaryInitializable { init(dict: [String: Any]) } 
  2. Make your two types conform to that type (you'll have to add required to your init methods, as prompted by Xcode), eg: 使您的两种类型符合该类型(您必须按照Xcode的提示添加init方法required ),例如:

     class Product: DictionaryInitializable { ... required init(dict: [String: Any]) { ... } } 

    and

     class ResPartner: DictionaryInitializable { static let fieldsResPartner = ... var attributes: [String: Any] = [:] required init(dict: [String: Any]) { for k in dict.keys where ResPartner.fieldsResPartner.contains(k) { attributes[k] = dict[k] } } func toString() { ... } } 
  3. Change your method declaration to make it clear that T must conform to your new protocol: 更改方法声明,以明确T必须符合您的新协议:

     func readAll<T: DictionaryInitializable>(objeto: String, typeClass: T.Type) -> [T] { var ret: [T] = [] ... // 2 while ( sqlite3_step(queryStatement) == SQLITE_ROW ) { var dict: [String: Any] = [:] ... ret.append(T(dict: dict)) // You can now use `T` here } return ret } 
  4. And you'd call it like: 你会这样称呼它:

     let list = db_respartner.readAll(objeto: "res_partner", typeClass: ResPartner.self) 

Create a Protocol with init Method 使用init方法创建协议

 protocol Mappable {       
        init(dictionary:[String:AnyObject]) // Changed based on your requirement.
 }

Conform your protocol in ResPartner. 在ResPartner中符合您的协议。

class ResPartner: Mappable {
    required init(dictionary : [String : AnyObject]) {
        // initialize here
    }
}

Conform your protocol in Product. 在Product中使用您的协议。

class Product: Mappable {
    required init(dictionary : [String : AnyObject]) {
        // initialize here
    }
}

Create a custom objects 创建自定义对象

func readAll<T:Mappable>(objeto: String, typeClass: T.Type) -> [T] {
        var ret : [T] = []

        // intialize your variable
        let obj = typeClass.init(dictionary: ["":"" as AnyObject])
        return ret
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM