I have a Plist which has endpoint URLs in it. I want to read that Plist and write it to my URLs struct after app opens and I want to reach these URLs in everywhere. Therefore, variables needs to be static. However, when I do var's static I get below error;
'static var' declaration requires an initializer expression or getter/setter specifier.
struct URLs: Codable {
static let urlBaseURL: String
static let urlCheckCMS: String
static let urlJSON: String
enum CodingKeys: String, CodingKey {
case urlBaseURL = "url_base_url"
case urlCheckCMS = "url_check_cms"
case urlJSON = "url_json"
}
}
// MARK: Convenience initializers
extension URLs {
init?(data: Data) {
guard let me = try? PropertyListDecoder().decode(URLs.self, from: data) else { return nil }
self = me
}
init?(_ plist: String, using encoding: String.Encoding = .utf8) {
guard let data = plist.data(using: encoding) else { return nil }
self.init(data: data)
}
init?(fromURL url: String) {
guard let url = URL(string: url) else { return nil }
guard let data = try? Data(contentsOf: url) else { return nil }
self.init(data: data)
}
var plistData: Data? {
return try? JSONEncoder().encode(self)
}
var plist: String? {
guard let data = self.plistData else { return nil }
return String(data: data, encoding: .utf8)
}
EDIT: In addition to below answer I change data init class with below code to get rid of optional. With below code, I check plist and If return nil when creating init class app won't continue to work;
init?(data: Data) {
guard let me = try? PropertyListDecoder().decode(URLs.self, from: data) else { return nil }
self = me
URLs.instance = me
}
and
static var instance: URLs!
But I'm still not sure this will be the best approach. As It is discussed in below post;
To fix your compiler errors, you should just provide a default value for your static members:
static let urlBaseURL: String = ""
However, there are a few major issues with your code. Using static members in a codable struct will not work as you think because coding/encoding always operates on instances of the struct, not on the struct type itself.
You should remove the static
from your vars and instead provide a singleton instance of URLs
which then can be read from all your app's components:
struct URLs: Codable {
static var instance? = nil
let urlBaseURL: String
let urlCheckCMS: String
let urlJSON: String
}
In your startup code you can set the value with:
URLs.instance = URLs(data: yourData)
And later you can access the values like with:
let urlBaseURL = URLs.instance?.urlBaseURL
Please note that the singleton pattern is commonly criticised, and for good reasons; in your case and for a start I think it's ok though.