0
votes

I have a core data background context that I use for fetching a large data from core data. I want to display a UIActivityIndicatorView while the data is being fetched.

My problem is, when I start the UIActivityIndicatorView before starting the fetch process and stop it after the fetching process, the activity indicator does not show in the screen. So I included a sleep(10) inside the background block just to make sure that the activity indicator has enough time to display, it doesn't show.

I know the activity indicator is loading by looking at the "Debug View Hierarchy" on xcode, it shows the activity indicator being in the view hierarchy on top.

This only happens when using it on a core data background context processes. On every other scenario, the activity indicator displays as expected.

Here is the code I'm using:

LoadingOverlay.shared.showOverlayWithMessage(self.view, message: "Loading ...")

let backContext = CDStack.shared.backgroundContext
backContext.performBlockAndWait { () -> Void in
    print("Fetching parts started ...")

    sleep(10)

    print("Fetching done!")
}

LoadingOverlay.shared.hideOverlayView()

The background context uses a parent context that has the NSPersistentStoreCoordinator with concurrencyType: .PrivateQueueConcurrencyType

I tried the following with no luck.

dispatch_sync(dispatch_get_global_queue(Int(QOS_CLASS_USER_INITIATED.rawValue), 0)) { () -> Void in

        let backContext = CDStack.shared.backgroundContext
        backContext.performBlockAndWait { () -> Void in
            dispatch_async(dispatch_get_main_queue()) { () -> Void in
                LoadingOverlay.shared.showOverlayWithMessage(self.view, message: "Loading ...")
            }
            print("Fetching parts started ...")

            sleep(10)

            print("Fetching done!")
            dispatch_async(dispatch_get_main_queue()) { () -> Void in
                LoadingOverlay.shared.hideOverlayView()
            }
        }
    }

Or the following:

dispatch_async(dispatch_get_main_queue()) { () -> Void in
    LoadingOverlay.shared.showOverlayWithMessage(self.view, message: "Loading ...")    
}
dispatch_sync(dispatch_get_global_queue(Int(QOS_CLASS_USER_INITIATED.rawValue), 0)) { () -> Void in

        let backContext = CDStack.shared.backgroundContext
        backContext.performBlockAndWait { () -> Void in

            print("Fetching parts started ...")

            sleep(10)

            print("Fetching done!")
        }
    }
dispatch_async(dispatch_get_main_queue()) { () -> Void in
    LoadingOverlay.shared.hideOverlayView()
}

I do not understand why the ActivityIndicatorView is not being displayed when used with core data background context activity. Help?

1

1 Answers

0
votes

In your examples what is happening is that the code where you load and dismiss your activity indicator is all on the main thread and so it is all being run immediately. The activity indicator is loaded and dismissed in the same breath so to speak. The main thread doesn't know about the other threads and vice versa, so if you look at your examples and totally ignore the background code you can see what I mean.

When you want the activity indicator to dismiss after the background code is finished running make sure to add the dismissal code in that background block

Eg

LoadingOverlay.shared.showOverlayWithMessage(self.view, message: "Loading ...")

let backContext = CDStack.shared.backgroundContext

backContext.performBlockAndWait { () -> Void in
    print("Fetching parts started ...")

    //fetching code

    print("fetching done")

    dispatch_async(dispatch_get_main_queue()) {
        self.LoadingOverlay.shared.hideOverlayView()
    }
}