How to wait till download from Firebase Storage is completed before executing a completion swift
Since loading the image data is an asynchronous operation, any code that needs to run after the images have loaded will need to be inside the completion handler, be called from there, or be otherwise synchronized.
A simple way is to count the number of images that have completely loaded, and call once it matches the length of the
array:
imageArray.removeAll()
for imageRef in products! {
let storageRef = self.storage.reference(withPath: imageRef.image!)
storageRef.getData(maxSize: 1 * 1024 * 1024) { [self] data, error in
if let error = error {
print (error)
} else {
//Image Returned Successfully:
let image = UIImage(data: data!)
//Add Images to the Array:
imageArray.append(image!)
// br> if (imageArray.count == products!.count) {
completion (true)
}
}
}
}
How to execute code directly after Firebase finishes downloading?
these network requests run async so any code after them will continue to run while the network request is being completed.
you should move updateCards.append(cards) inside the inner closure so it doesn't get called until that second closure finishes, then if you have other code you need to run when this is complete you can either move it inside of this function or use a closure with a completion handler to make sure all network requests are completed before you run any more code the relies on the response.
getCardData { [weak self] in
// do whatever you need to do after completion
}
func getCardData(_ completion: () -> ()) {
print("Feed: button donwloading cards")
//self.databaseButton.setTitle("Downloading New Cards...", for: .normal)
ref.observe(.value, with: { snapshot in
print("Feed: Checking for new cards from firebase")
for item in snapshot.children {
// Download in memory with a maximum allowed size of 1MB (1 * 1024 * 1024 bytes)
cardRef.data(withMaxSize: 1 * 1024 * 1024) { (data, error) -> Void in
if (error != nil) {
// Uh-oh, an error occurred!
print("Feed: error occured")
print(error)
completion() // this is where you would normally throw an error or have a closure that accepts an optional error you would pass in to know it failed
} else {
// Data for "images/island.jpg" is returned
cards.imageName = data!
print("Feed: downloaded \(cards.name)")
updateCards.append(cards);
completion()// now you know all network requests are complete
}
}
}
})
}
How to do some action when image from firebase is stored in storage
StorageReference's getFile(File destinationFile) method returns a FileDownloadTask
object which is actually a Task.
To solve you can use Tasks's whenAllSuccess(Collection> tasks) method like this:
List<Task<?>> tasks = new ArrayList<>();
tasks.add(downloadRef.getFile(file1));
tasks.add(downloadRef.getFile(file2));
tasks.add(downloadRef.getFile(file3));
//And so on
Tasks.whenAllSuccess(tasks).addOnSuccessListener(new OnSuccessListener<List<Object>>() {
@Override
public void onSuccess(List<Object> list) {
//Do what you need to do with your list
for (Object object : list) {
//Show images
}
}
});
How does control flow work when retrieving Information from Firebase?
It's the logic of asynchronous calls
print("1") // empty
refBluetezeit.child("Februar").observeSingleEvent(of: .value, with: { snapshot in
print("3") // empty
for plant in snapshot.children {
self.ergebnisBluetezeit.insert((plant as AnyObject).value)
}
print(ergebnisBluetezeit) // not empty
})
print("2") // empty
the value is empty until the request finishes regardless of where in code ordering you run the print , as the numbering above in order 1 , 2 , 3 to know when it finishes you can use completions like
func getData(completion:@escaping() -> ()) {
let refBluetezeit = rootRef.child("Pflanzen").child("Eigenschaften").child("Blütezeit")
refBluetezeit.child("Februar").observeSingleEvent(of: .value, with: { snapshot in
for plant in snapshot.children {
self.ergebnisBluetezeit.insert((plant as AnyObject).value)
}
completion()
})
}
And call
getData {
print(ergebnisBluetezeit)
}
Firebase: How to implement take action only when another device is online ?
You already seem to have the best approach with built-in primitives, i.e. Firebase's presence system. One note on the onDisconnect
though: it will only take that long to detect a dirty disconnect (app crashes, network connection lost, etc). In the case of a clean disconnect (app is closed), the onDisconnect
should fire almost immediately.
If the way the onDisconnect
behaves is not good enough for your needs, you will need to implement the rest inside your app.
The first thing that came to mind is an active keep-alive, which seems to be what you already use in #2. Given that you want a latency of at most 3 seconds, your 2 second keep-alive ping seems like a reasonable interval.
This will indeed increase your bandwidth usage. Given your use-case and the way the platform works, I don't see any other way to implement it though.
Related Topics
Swift 3 Error:Argument Labels '(_:)' Do Not Match Any Available Overloads
Swift Equivalent to _Attribute((Objc_Requires_Super))
Uitableviewcell: Rounded Corners and Shadow
How to Convert Range in Nsrange
In Swift, How to Cast to Protocol with Associated Type
How to Connect to Self Signed Servers Using Alamofire 1.3
Swift: Extending Functionality of Print() Function
Programmatically Screenshot | Swift 3, Macos
How to Configure Contextmenu Buttons For Delete and Disabled in Swiftui
Uiwebview Dynamic Content Size
Is Swiftui Backwards-Compatible With iOS 12.X and Older
In Swift, What Does the ! Symbol Mean in a Function Signature
Swiftui: Pop to Root View When Selected Tab Is Tapped Again
Extension May Not Contain Stored Property But Why Is Static Allowed
Passing Data Between Tab Viewed Controllers in Swift
Interface Builder, @Iboutlet and Protocols for Delegate and Datasource in Swift