这是我的挑战:我有一个结构。这是使用FirebaseDatabase中的documentSnapshot初始化的。 Struct返回一个数组,然后将其填充到“集合视图”中
这很好,直到我试图将两个图像添加到数组中为止。它们存储在Firebase存储中。初始化时,引用键将传递到结构中(它们在这里,我测试过)。但是,创建myArray时,图像不存在。没有错误信息。 struct / array的所有其他部分都可以正常工作(距离计算等)
感谢任何人的帮助
struct myStruct {
var myArray = [Any]()
init?(Name: String, Amount: String, Description: String, SecondName: String, RID: String, GeoPoint: GeoPoint, DID: String) {
var location = CLLocation()
var myArray = [Any]()
var distance: Double
var imageA = UIImage()
var imageB = UIImage()
let refA = Storage.storage().reference().child("Images").child(todayDate).child(DID)
refA.getData(maxSize: 1000 * 1240 * 1240) { data, error in
if let error = error {
print(error.localizedDescription)
} else {
imageA = UIImage(data: data!)!
}
}
let refB = Storage.storage().reference().child("Icons").child(RID)
refB.getData(maxSize: 1000 * 1240 * 1240) { data, error in
if let error = error { print(error.localizedDescription)
imageB = (UIImage(named: "DefaultIcon.png") as UIImage?)!
} else {
imageB = UIImage(data: data!)!
}
}
location = CLLocation(latitude: GeoPoint.latitude, longitude: GeoPoint.longitude)
distance = round(location.distance(from: userLocation)/10)*10
myArray = [Name, Amount, Description, SecondName, String(Int(distance)), GeoPoint, imageA, imageB]
self.menuItem = menuItem
}
}
答案 0 :(得分:0)
看起来,您的结构要完全实例化,需要先等待两个异步数据任务才能完成(获取图像)。由于您启动了它们,但不必等待它们完成,因此在您将数据写入阵列时,图像数据根本不可用。
有很多可能的方法可以解决这种时间依赖性。哪个是最适合您的项目的选择,很大程度上取决于您的用例和体系结构的整体选择。
但是,一般而言,将此类异步数据任务保留在结构的init
中是一个好主意,而是在负责创建和管理您的结构的任何类中执行它们。然后将获取的图像作为init参数传递给struct。
这是您的处理方式,以稍微抽象的方式进行了演示:
您当前可能在代码中的某个位置带有一个对象,该对象具有创建和存储类似于以下内容的MyStruct
的功能:
func loadMyStruct() {
self.myStruct = MyStruct(...)
}
该结构创建函数的更好替代方法是:
func loadMyStruct(completion: @escaping ()->Void) {
DispatchQueue(label: "MyStructDataFetch", attributes: .concurrent).async { [weak self] in // don't block main thread waiting for data tasks to finish
let dispatchGroup = DispatchGroup() // since we're waiting on two parallel async tasks, we can use a DispatchGroup to group them together
var imageA: UIImage?
var imageB: UIImage?
dispatchGroup.enter() // enter DispatchGroup
let refA = Storage.storage().reference().child("Images").child(todayDate).child(DID)
refA.getData(maxSize: 1000 * 1240 * 1240) { data, error in // start 1st data task
if let error = error {
...
} else {
imageA = UIImage(data: data!)!
}
dispatchGroup.leave() // 1st task is done; leave DispatchGroup
}
dispatchGroup.enter() // enter DispatchGroup
let refB = Storage.storage().reference().child("Icons").child(RID)
refB.getData(maxSize: 1000 * 1240 * 1240) { data, error in // start 2nd data task
if let error = error {
...
} else {
imageB = UIImage(data: data!)!
}
dispatchGroup.leave() // 2nd task is done; leave DispatchGroup
}
let _ = dispatchGroup.wait(timeout: DispatchTime.distantFuture) // wait for all tasks to be done, then...
self?.myStruct = MyStruct(imageA: imageA, imageB: imageB, ...) // ... pass the finished images to MyStruct constructor
completion() // Optional: notify observer (e.g. UI) that "MyStruct" is now ready to use
}
}
相应地调整了结构的初始化:
init?(imageA: UIImage?, imageB: UIImage?, ...) {
...