我正在尝试创建一个通用函数来获取不同的集合,并基于给定的类型,让我们说T
将所有文档转换为T
,然后填充并返回一个数组。
问题是在这行let item: T = T.init(document: document)
上,即使没有Type 'T' has no member 'init'
,我也会收到一条错误消息,说.init
失败。
这是将传递给该泛型函数的类型的示例。
struct Package: Identifiable {
var id = UUID()
let documentReference: DocumentReference
init(document: DocumentSnapshot) {
self.documentReference = document.reference
}
这是我的代码:
static func fetchCollection<T>(collection: String, completion: @escaping ([T]) -> Void) {
var array: [T] = []
db.collection(collection).getDocuments() { (querySnapshot, err) in
if let snapshot = querySnapshot {
guard let userID = Auth.auth().currentUser?.uid else { return }
for document in snapshot.documents {
let item: T = T.init(document: document)
array.append(item)
}
completion(array)
}
}
}
函数调用:
FirebaseViewModel.fetchCollection<Package>(collection: "packages") { packages in
self.userData.packages = packages
}
最佳答案
编辑
顶级方法签名中的泛型不能约束为struct,因此将需要协议抽象。
创建PackageProtocol
protocol PackageProtocol {
init(document: DocumentSnapshot)
}
使Package
符合PackageProtocol
struct Package: PackageProtocol
将方法签名更改为:static func fetchCollection<T: PackageProtocol>(collection: String, completion: @escaping ([T]) -> Void)
原始答案在您的上下文中, T 完全不受任何类型的约束,因此它无法识别您的初始化程序。
我将方法签名更改为:
static func fetchCollection<T == Package >(collection: String, completion: @escaping ([T]) -> Void)
或者如果您期望使用不同类型的Package
static func fetchCollection<T: Package >(collection: String, completion: @escaping ([T]) -> Void)