15

My problem is that I need to get this specific variable to be initialized no matter what, because there's another object that depends on this variable's value

Here's the code (I set the variable as global)

lazy var getToken = {
        if let token = keychain["token"].string {
            return token
        }
    }()

I'm using lazy because I need this to get initialized no matter what.

I got this error error When I trying to put it on a global file

'lazy' may not be used on an already-lazy global

Here's the object that is depending on this token

Singleton Design

class SocketIOManager: NSObject {

    static let sharedInstance = SocketIOManager()

    let socket: SocketIOClient!

    private override init() {
        super.init()
        socket = SocketIOClient(socketURL: URL(string: mainURL)!, .connectParams(["token": getToken])])
  }
}

If you take a look at socket = at "token", that's where I need the token

rmaddy
  • 314,917
  • 42
  • 532
  • 579
airsoftFreak
  • 1,450
  • 5
  • 34
  • 64

2 Answers2

16

IMPORTANT

user2908517's answer is totally wrong. so request to read this once.

According to docs https://docs.swift.org/swift-book/LanguageGuide/Properties.html

Global constants and variables are always computed lazily, in a similar manner to Lazy Stored Properties. Unlike lazy stored properties, global constants and variables do not need to be marked with the lazy modifier.

Local constants and variables are never computed lazily.

Which means Global constants and variables not class properties they are both different just like the ocean and river. Request to read https://stackoverflow.com/a/33837338/4601900

Class properties are not lazy by default, class property automatically init when it's init method called either designated or convenience.

I don't understand why you are putting lazy over there ?

Lazy can be used when you want to initialize a variable when they actually needed by compiller .

Other then lazy type (normal var) will be initialize as soon as designated initializer called

You can use

var getToken : String? = { if let token = keychain["token"].string { return token } }
lbarbosa
  • 2,042
  • 20
  • 23
Prashant Tukadiya
  • 15,838
  • 4
  • 62
  • 98
  • You cant initialize variable using closure, func, or another property unless you using "lazy" in Swift 4 – Krypt Mar 28 '19 at 07:47
  • @Krypt Can you please elaborate ? , Did you read the question he want to init variable anyhow. And lazy can't be solution here. because lazy will be init only when used first time (delays the init) unlike stored property – Prashant Tukadiya Mar 28 '19 at 07:50
  • @Krypt Answer is computed property. and Answer provided by User2908517 is totally wrong, property is not by default lazy , Global variables are see this https://stackoverflow.com/a/33837338/4601900 – Prashant Tukadiya Mar 28 '19 at 07:58
  • You asked "why you are putting lazy over there?" I'm answered on this question: because you unable to assign inline something complex. You need to assign it using init() or to make property lazy – Krypt Mar 28 '19 at 08:36
  • @Krypt **zYou need to assign it using init() or to make property lazy** I agree but only for stored property. If you are using computed property then you don't need to do that. and here in question he need computed property neither lazy nor stored :0 – Prashant Tukadiya Mar 28 '19 at 09:29
7

I am not sure what you mean by "I'm using lazy because I need this to get initialized no matter what.", but all global variables are lazy by default, that is why no need (and not allowed) to place keyword "lazy" before the global variable declaration: they are already lazy by their nature.

user2908517
  • 508
  • 4
  • 8
  • How about this error `Unable to infer complex closure return type; add explicit type to disambiguate` – airsoftFreak Nov 19 '17 at 05:39
  • I removed lazy and now I got this problem – airsoftFreak Nov 19 '17 at 05:39
  • "add explicit type" to your variable getToken – user2908517 Nov 19 '17 at 05:42
  • `var getToken: String = { if let token = keychain["token"].string { return token } return "default token" }()` or simply `return keychain["token"].string ?? "default token" ` – Leo Dabus Nov 19 '17 at 05:55
  • How u can say that all global variable are lazy by default ? This is not true – Prashant Tukadiya Nov 19 '17 at 06:23
  • 2
    Global constants and variables are always computed lazily, in a similar manner to Lazy Stored Properties. Unlike lazy stored properties, global constants and variables do not need to be marked with the lazy modifier - form https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/Properties.html – user2908517 Nov 19 '17 at 06:41
  • @user2908517 Sorry You misunderstood here, Doc you provided is for **GLOBAL** property which is diff. than class property See this https://stackoverflow.com/a/33837338/4601900 – Prashant Tukadiya Mar 28 '19 at 07:55
  • This may have changed since this question was posted, but as of now (Swift 5.4), class properties are also lazy by default. See the [Swift Documentation](https://docs.swift.org/swift-book/LanguageGuide/Properties.html#ID264) for reference. Under "Note" it states "Stored type properties are lazily initialized on their first access. They’re guaranteed to be initialized only once, even when accessed by multiple threads simultaneously, and they don’t need to be marked with the `lazy` modifier." – iComputerfreak Mar 12 '21 at 18:25