[英]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: 您可以使用协议约束您的泛型:
Define a protocol for initializing with a dictionary: 定义用字典初始化的协议:
protocol DictionaryInitializable { init(dict: [String: Any]) }
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() { ... } }
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 }
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.