progressBlock in getDataInBackgroundWithBlock not called - ios

My Swift app uses Parse.com as the backend. Among other things, I store images for user profiles. I store two versions of the same image: one thumbnail and one full sized image. When the user taps on the thumbnail, it is enlarged. The app then loads the full sized version and presents it on top of the enlarged thumbnail when loading is complete. Since the thumbnail image looks blurry while the full sized one is loading, I've implemented a circular progress bar that shows the loading progress, giving visual feedback of what's going on.
This is the method that handles this process (progressCircle is a CAShapeLayer):
func fetchFullImage() {
photoObject.fetchIfNeededInBackgroundWithBlock { (fetchedObject: PFObject!, error: NSError!) -> Void in
if error == nil {
// After fetching object, now we get the full sized image
let userFullImageFile = fetchedObject["fullImage"] as PFFile
userFullImageFile.getDataInBackgroundWithBlock( {
(imageData: NSData!, error: NSError!) -> Void in
if error == nil {
println(">> Success! Full image retrieved.")
self.fullImageView.image = UIImage(data: imageData)
// Hide the progress indicator
self.progressCircle.hidden = true
// Fade in and show the image
self.showFullImage()
}
},
progressBlock: {(percentDone: CInt) -> Void in
println("Loading... \(percentDone)")
// Prints out progress percentage under wifi, but not under 3G!
self.progressCircle.strokeEnd = CGFloat(percentDone) / 100.0
})
} else {
println(error)
}
}
}
Now this is the funny part. When I run the app on a real device connected via wifi, everything goes as expected: the progress circle grows as the image is loaded, etc. Now when I turn off wifi and the same device is connected via 3G, the progress circle does not grow. Essentially, what happens is that the progressBlock closure is not called (I can see this because the println statement produces no result). The image loads after a while (the completion closure is called), and is presented correctly, but there is no way for me to show the progress.
I am trying to find the logic behind this. I could almost understand it if it was the opposite (image loading so fast over wifi that the progress was not visible), but over 3G images take a few seconds to load, during which period nothing seems to happen.
Does anyone have an idea of what can keep progressBlock from being called here? I want to be able to provide the "loading in progress" visual feedback.
Thanks in advance!

Related

WKInterfaceMap blank rendering

WKInterfaceMap sometimes renders blank in a very simple app I am developing. The map appears completely empty (no grid of lines or anything similar). It looks as though the thread responsible for drawing the tiles gets blocked.
In order to reproduce the issue just add the code below to the extension delegate.
func applicationDidEnterBackground() {
let watchExtension = WKExtension.shared()
// Schedule the background refresh task.
watchExtension.scheduleBackgroundRefresh(withPreferredDate: Date().addingTimeInterval(15.0*60.0), userInfo: nil) { (error) in
// Check for errors.
if let error = error {
print("ExtensionDelegate: \(error.localizedDescription)")
return
}
print("ExtensionDelegate: Background Task scheduled successfuly")
}
}
Add a WKInterfaceMap to the main view and run once on the simulator. Close the app using the crown and stop it from XCode. Wait for at least 15 minutes and open the app again directly from the simulator.
The map renders then as in the image below.

Slow loading of images in UITableViewCell since Xcode 11

We have an application that has been running for years using UITableViewCells containing thumbnail images stored locally. The loading of images was never a problem and scrolling was fast. Since the latest Xcode update it has become sticky and images are loading slowly. I've implemented asynchronous loading to try and solve this and scrolling is smooth but there is a significant lag in loading images which is unacceptable.
Has anyone else experienced this? What has changed in Xcode 11 to cause this?
For what it's worth, here is the code I have now:
DispatchQueue.global(qos: .background).async {
let ImageLoaded = g_resources.readTreeImage(id: UInt(initData.IconImageID) ?? 0)
if(initData.IconImageID != nil)
{
DispatchQueue.main.async(execute: {() -> Void in
self.m_treeImageView.image = ImageLoaded
})
}
}

ReplayKit stops buffering after going to background repeatedly

I'm trying to use ReplayKit to create a live broadcast inside of my app.
Basically I want to share my screen and see the screen of the other user.
To get the buffers, ReplayKit offers the next function:
func startCapture(handler captureHandler: ((CMSampleBuffer, RPSampleBufferType, Error?) -> Void)?, completionHandler: ((Error?) -> Void)? = nil)
So this is my method to startup ReplayKit and get the buffers:
private func startRecording() {
RPScreenRecorder.shared().startCapture(handler: { (sampleBuffer, bufferType, error) in
switch bufferType {
case RPSampleBufferType.video:
// Handle buffer and send it to server
break
case RPSampleBufferType.audioApp:
break
case RPSampleBufferType.audioMic:
break
}
}, completionHandler: nil)
}
This works perfectly, but I'm facing the next issue; if the screen gets changes constantly, like a flashing button, when I send the app to background and come back several times ReplayKit stops calling its capture handler.
Maybe the problem is that the function startCapture is made to record the screen for a limited time, and not for a live broadcast.
I have made an example in Github with a flashing button that shows the problem that I'm having; ReplayKit runs normally until going to background repeatedly; then it stops, and the only way to make it work again is to reboot the device.

Firebase Storage download task is not completing after the app has spent some time in the background

I am downloading an image from Firebase storage as follows:
let storage = FIRStorage.storage()
// Create a storage reference from our storage service
let storageRef = storage.reference(forURL: "MY_STORAGE_URL")
let imageRef = storageRef.child("Path_to_image")
// Download image in memory
let downloadTask = imageRef.data(withMaxSize: 1 * 1024 * 1024) {
(data, error) -> Void in
if (error != nil) {
//Handle the error
} else {
guard let imageData = data else {
print("Unable to unwrap image data.")
return
}
let downloadedImage = UIImage(data: imageData)
//Do some stuff with the image
}
}
I am also monitoring what happens with the download using the following observers:
// Observe changes in status
downloadTask.observe(.resume) { (snapshot) -> Void in
// Download resumed, also fires when the download starts
}
downloadTask.observe(.pause) { (snapshot) -> Void in
// Download paused
}
downloadTask.observe(.progress) { (snapshot) -> Void in
// Download reported progress
}
downloadTask.observe(.success) { (snapshot) -> Void in
// Download completed successfully
}
downloadTask.observe(.failure) { (snapshot) -> Void in
//Download failed
}
This all works just fine when the app is first started. However, I am getting problems if the app enters the background and I play around with some other applications (Facebook, Twitter, etc.), then bring the app back to the foreground. I also have problems if I leave the app open and running in the foreground for greater than or equal to 1 hour.
The problem is that the completion handler in let downloadTask = imageRef.data(withMaxSize: blah blah blah (in the first block of code above) is never called. If the completion handler is never called, I can never unwrap the data and attempt to use the image in my application.
Also, in the downloadTask observers, the only completion handlers that get fired are .resume and .progress. The .success or .failure events are never triggered. This seems to be a Firebase Storage bug to me, but I am not sure. Has anyone else encountered a similar issue? I don't understand why the code would work just fine from a fresh launch, but then after some time in the foreground or after some time in the background the image download stops working. Thanks in advance for any input you may have.
This is currently the expected behavior, unfortunately. Firebase Storage (at present) is foreground only: if the app is backgrounded, we haven't persisted the upload URL, and can't upload in the background nor restart it after it gets out of the background, so it probably is killed by the OS and the item isn't uploaded.
It's The Next Big Thing™ we'd like to tackle (our Android SDK makes it possible, though not easy), but unfortunately for now we haven't made more progress on this.
As a bit of a side note, your observers won't exist after the activity change--downloadTask is gone once the app is backgrounded, so when it comes back into the foreground, we basically need a method that retrieves all tasks that are currently backgrounded, and allows you to hook observers back up. Something like:
FIRStorage.storage().backgroundedTasks { (tasks) -> Void in
// tasks is an array of upload and download tasks
// not sure if it needs to be async
}

Failed to get images from camera DJI OSMO

I'm working with DJI sdk to get the photographs taken with the camera osmo. The problem I have is that when I show a picture on the screen gives me the following error:
"ERROR: fetchThumbnailWithCompletion: ErrorDomain DJISDKErrorDomainCode = -1004 =" System is busy, Please retry later (Code: -1004). ""
So it is written in the sdk:
#IBAction func onShowThumbnailButtonClicked(sender: AnyObject) {
self.showThumbnailButton.enabled = false
if self.imageMedia?.thumbnail == nil {
// fetch thumbnail is not invoked yet
self.imageMedia?.fetchThumbnailWithCompletion({[weak self](error: NSError?) -> Void in
if error != nil {
self?.showAlertResult("ERROR: fetchThumbnailWithCompletion:\(error!.description)")
}
else {
self?.showPhotoWithImage(self!.imageMedia!.thumbnail!)
}
self?.showThumbnailButton.enabled = true
})
}
}
But I need to show 6 images, therefore I make 6 times (6 times using a do) what is inside the IBAction. Then at that time the error occurs, because if I do it only once that error does not happen.
In addition, selecting ok error that appears like still works for other images but the idea is that no such error appears.
Any idea how to fix it?
Please ensure you have switched the camera to download mode (https://developer.dji.com/iframe/mobile-sdk-doc/ios/Classes/DJICamera.html). If you have already done that, then add delay between photo shooting and download.

Resources