static property in AppDelegate

Hi!

Im asking me, if it would be a good idea to make a statement like this in my AppDelegate to access that particular instance of NSManagedObjectContext (AppDelegate.myContext….):


@class AppDelegate: UIResponder, UIApplicationDelegate {
     ...
     static let myContainer = NSPersistentContainer(name:”myContainer”)
     static let myContext = myContainer.viewContext
     ...
}


Then I can acces that instance via


AppDelegate.myContext


Is that rather mindless?


Or should I write


@class AppDelegate: UIResponder, UIApplicationDelegate {
     var myContainer = NSPersistentContainer(name: "myContainer")
     var myContext = NSManagedObjectContext?
     ...
     func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
          ...
          myContext = myContainer.viewContext
          ...
     }
     ...
}


Is that rather pointless?


Which way should I prefer?


Best regards!

Accepted Reply

Hi Strike, Unfortunately that approach will not actually allow you to access one specific instance of the viewContext, because static variables are "reinitialized" (different instances) every time you access them. You should be able to simply make the persistentContainer and viewContext non-static and optional, using the following declaration: var context : NSManagedObjectContext? It may seem tedious to check the existence of that instance whenever you wish to use it, but the safety it affords you is priceless.

Replies

Hi Strike, Unfortunately that approach will not actually allow you to access one specific instance of the viewContext, because static variables are "reinitialized" (different instances) every time you access them. You should be able to simply make the persistentContainer and viewContext non-static and optional, using the following declaration: var context : NSManagedObjectContext? It may seem tedious to check the existence of that instance whenever you wish to use it, but the safety it affords you is priceless.

Thanks a lot!

It may seem tedious to check the existence of that instance whenever you wish to use it, but the safety it affords you is priceless.

I disagree with this. One of the nice things about Swift optionals is that they let you constrain the possible points of failure. This example is a perfect illustration of that.

Is your app going to be able to do anything useful without this managed context? If not, you should set the context up in ‘will finish launching’ and make it an implicitly unwrapped optional. If the initial setup process fails, your app should handle the error then and there. After that point the rest of your code can safely assume that the context is available and use it via the implicitly unwrapped optional property.

So, here’s how I’d structure the code:

class AppDelegate … {

    var context: NSManagedObjectContext! = nil

    func application(_ application: UIApplication, willFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey : Any]? = nil) -> Bool {
        guard let localContext = … create the context … else {
            … handle the error …
        }
        // Set the implicitly unwrapped optional.  From now on every other part 
        // of your app can assume that the managed object context exists.
        self.context = localContext
        return true
    }

    …
}

Well, actually, I’d move the managed object context out of the app delegate and in to some controller object that’s specifically responsible for managing my CoreData stack, but the same logic would apply there as well.

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"

Oh.


Thank you for this clarification! Actually I'm using the mechanism you've described:


class ODDataManagement: NSObject {
     ...   
     var managedObjectContext: NSManagedObjectContext! = nil
     var managedObjectModel: NSManagedObjectModel! = nil
     ...
}

class AppDelegate: UIResponder, UIApplicationDelegate {
     ...

     var dataController: ODDataManagement! = nil
     ...

     func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
        dataController = ODDataManagement()
       /* 
         error handling
       /*

        ...     
        return true
    }

Although I agree that it is better to have those things stored as instance properties of the app delegate or a controller, the following statement doesn't seem accurate, and sounds like the opposite of how type properties actually work.

rjuniyer:
Unfortunately that approach will not actually allow you to access one specific instance of the viewContext, because static variables are "reinitialized" (different instances) every time you access them.


https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/Properties.html


"You can also define properties that belong to the type itself, not to any one instance of that type. There will only ever be one copy of these properties, no matter how many instances of that type you create. These kinds of properties are called type properties.

Type properties are useful for defining values that are universal to all instances of a particular type, such as a constant property that all instances can use (like a static constant in C), or a variable property that stores a value that is global to all instances of that type (like a static variable in C)."


"Stored type properties are lazily initialized on their first access. They are guaranteed to be initialized only once, even when accessed by multiple threads simultaneously [...]"

Hi LCS,


Thanks for that clarification, I didn't know how to describe it any better, but I meant that there is only one instance of the static class ever in existence at one time. I wasn't sure if the class is deinitialized after the access, so I called that concept "reinitialization".

Hi eskimo,


Thanks for the clarification, I didn't even know how to make an explicitely unwrapped optional; that's pure magic!


This will save me a bunch of time, I had been wrapping a lot of my options with ifs.


Behold the power of guard!!


Thanks again