0

My main issue revolves around dispatch_once. I am converting this objective-c code in Swift :

dispatch_once(&_startupPred, ^{
        [MPPush executeUnsafeStartupWithConfig:[MPConfig configWithAppKey:appKey withAppId:appID withAccountId:accountId forProduction:inProduction] authToken:authToken];
    });  

Swiftify doesn't help much. So I dig a bit deeper. Apparently dispatch_once is no longer in Swift. As per this accepted answer, I can achieve this by :

let executeStartup = {
            self.executeUnsafeStartupWithConfig(config: MPConfig.config.configWithAppKey(appKey: appKey, withAppId: appId, withAccountId: accountId, forProduction: inProduction), authToken: authToken)
        }()

_ = executeStartup  

But by doing so, I get this warning :

Constant 'executeStartup' inferred to have type '()', which may be unexpected

So first, is this the correct way of replacing dispatch_once in Swift ? Secondly how do I handle this warning ?

Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
Nitish
  • 13,845
  • 28
  • 135
  • 263
  • Can you not just put this code in a function like `didFinishLaunching` where it will only execute once? – Paulw11 Oct 03 '18 at 06:42
  • @Paulw11 : And what would that function be ? I have other places as well where that would be used ? I can't place all in didFinishLaunching. – Nitish Oct 03 '18 at 07:00
  • The purpose of the dispatch once block is to ensure that the given block of code runs only once in the apps lifetime. The typical use in Objectice C was to initialise singletons. The code you have shown seems to be doing something like that, so performing that initialise in `didFinishLaunching` should satisfy your requirements. – Paulw11 Oct 03 '18 at 07:03
  • @Paulw11 : Makes sense. But is there any way to do that at a class level ? I don't want to touch the AppDelegate for that matter. – Nitish Oct 03 '18 at 07:04
  • 1
    To do it in a class you would need to adopt a singleton pattern. Create a static instance of that class as a class property and then do whatever you need in the classes initialiser. What you have in your answer is a global solution which will also work. You need to declare the type of `executeStartup` as, say, `Void` – Paulw11 Oct 03 '18 at 07:15

2 Answers2

1

Yes this is one of the ways you can replace dispatch_once. For your specific use case you can consider placing this code where it will only be executed once in the lifecycle of the app, which is probably the best approach for your use case.

If you just want to get rid of the warning you can declare the type of executeStartup as Any

let executeStartup : Any = {
        self.executeUnsafeStartupWithConfig(config: MPConfig.config.configWithAppKey(appKey: appKey, withAppId: appId, withAccountId: accountId, forProduction: inProduction), authToken: authToken)
    }()
nishith Singh
  • 2,968
  • 1
  • 15
  • 25
  • How does it ensure it would be called just once ? – Nitish Oct 03 '18 at 06:59
  • This concept is called Lazy Initialization with Closures you can refer this blocg for details https://blog.bobthedeveloper.io/swift-lazy-initialization-with-closures-a9ef6f6312c. To sum up this is lazy and once in a lifetime initialization and will happen only once in the app lifecycle – nishith Singh Oct 03 '18 at 07:10
1

This will definitely execute the block once and you can specify the type as Void so that compiler does not complain.

let executeStartup: Void = {
    self.executeUnsafeStartupWithConfig(config: MPConfig.config.configWithAppKey(appKey: appKey, withAppId: appId, withAccountId: accountId, forProduction: inProduction), authToken: authToken)
 }()

You can also use lazy var executeStartup: Void as this will also ensure the block is executed once.

Kamran
  • 14,987
  • 4
  • 33
  • 51