(Cocoa, Swift) How to run piece of code *before* any other app code ?

Discussion in 'Mac Programming' started by 0002378, Sep 12, 2017.

  1. 0002378 Suspended

    0002378

    Joined:
    May 28, 2017
    #1
    There is some app configuration code (e.g. ensuring that all logging is done to a specific file) that needs to run before any other app code is run. It needs to be the very first piece of my code that is run.

    Now, it is not enough for me to put this in AppDelegate.applicationDidFinishLaunching() because certain other app code (object init()) runs before the app finishes launching. In other words, didFinishLaunching() is too late in the app lifecycle for my purposes.

    So, basically, I'm trying to find a way to hook into the application life cycle stage that occurs before the app launches (and any other app code runs). I have looked at and tried implementing all NSApplicationDelegate lifecycle methods, with no luck. Ideally, there would be an NSApplicationDelegate method like applicationWillLaunch(), but there isn't one (there is applicationWillFinishLaunching, but that is too late).

    I have achieved this, tentatively, by subclassing NSApplication and overriding its init() method. This works, but is there a better way ? Is there a method either in NSApplication or NSApplicationDelegate that I can implement/override that will execute before the app begins launching ?

    Thanks !
     
  2. Krevnik macrumors 68040

    Krevnik

    Joined:
    Sep 8, 2003
    #2
    Depending on what you are trying to do, there are a couple ways:

    1) Lazy initialization. Have the action of getting "the current logger" object initialize the logger if there isn't already a current logger. This can use the singleton pattern, and while not ideal, at least leaves all the code localized to the logger component itself. At least as a first pass without knowing more details, this is my first choice.

    2) You can either override NSApplication's init like you have, or NSApplication's run. This is my second choice, as it does the job, but tends to violate locality.

    3) Swift supports code that lies outside of a function (it's how Playgrounds work). It should get executed prior to NSApp.run() is executed by Apple. This is my last choice, since this is relying on implicit behavior in Swift, and while it should work, it tends to make the code a little less clear.

    In general, whenever I've got global state like loggers, I tend to fall onto the Singleton pattern with lazy initialization and then refactor as needed to see if I can clean it up after that.
     
  3. 0002378 thread starter Suspended

    0002378

    Joined:
    May 28, 2017
    #3
    Thanks.

    With reference to your point #1, that sounds a lot like how logging is done in Java, but in my Swift code, all I'm doing is:

    Code:
    NSLog(myLogMessage)
    So, I'm not really initializing the logger myself.

    My configuration code, which needs to run first, is the following:

    Code:
    // Make sure all logging is done to the app's log file
        private func configureLogging() {
            
            let allPaths = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)
            let documentsDirectory = allPaths.first!
            let pathForLog = documentsDirectory + ("/" + AppConstants.logFileName)
            
            freopen(pathForLog.cString(using: String.Encoding.ascii)!, "a+", stderr)
        }
    I ended up putting this in AppDelegate.init().

    So, I guess I'm saying I didn't understand your #1 suggestion. I'm not doing any logger initialization; I'm simply using NSLog() whenever I need to log something.

    BTW, I'm a huge fan of the Singleton pattern and use it a lot.
     
  4. 960design, Sep 13, 2017
    Last edited: Sep 13, 2017

    960design macrumors 68030

    Joined:
    Apr 17, 2012
    Location:
    Destin, FL

Share This Page

3 September 12, 2017