Reputation: 12992
I'm here to understand why the solution I had implemented won't work. Basically I have a class called MyClass
and in this class I'd like to have a static dictionary created from a plist file. Like this:
class MyClass {
static var myDic: [String: String] = NSDictionary(contentsOfFile: Bundle(for: self).path(forResource: "filename", ofType: "plist")!) as! [String: String]
}
If I do so, compiler will complain that:
Cannot convert value of type '(MyClass) -> () -> (MyClass)' to expected argument type 'AnyClass' (aka 'AnyObject.Type')
But if I change myDic
var and create a static method returning that dic, all is fine:
class MyClass {
static func myDic() -> [String: String] {
return NSDictionary(contentsOfFile: Bundle(for: self).path(forResource: "PlayerRolesWithColors", ofType: "plist")!) as! [String: String]
}
}
Two questions here:
'(MyClass) -> () -> (MyClass)'
Thanks.
Upvotes: 2
Views: 1707
Reputation: 20274
Lets look at a simpler (working) example keeping your core issue the same:
class ClassName {
static var bundle = Bundle(for: ClassName.self)
static func getBundle() -> Bundle {
return Bundle(for: self)
}
}
Firstly, lets note that Bundle(for: AnyClass)
takes an object type.
Variables at top-level, access self
as ClassName
which is an instance type, whether it is declared as let
/var
/lazy
/computed, static or not.
So:
static var bundle = Bundle(for: self)
is same as:
static var bundle = Bundle(for: ClassName())
Both are invalid and generate the following error:
Cannot convert value of type 'ClassName' to expected argument type 'AnyClass' (aka 'AnyObject.Type')
For sure, this is because we're passing an instance type instead of the expected Object type.
static var bundle = Bundle(for: ClassName.self)
As for a static function, this is a bit different.
The metatype that you call the static method on is available to you in the method as
self
(it's simply passed as an implicit parameter).
In my example, we have:
static func getBundle() -> Bundle {
return Bundle(for: self)
}
When you call ClassName.getBundle()
, ClassName.Type
is implicitly passed to the function.
Now within the static function, self
is of type ClassName.Type
which is an Object type and can be applied directly in Bundle(for:)
, or similar functions that accept an Object type as it's parameter.
So, static functions access self
as ClassName.Type
which is same as ClassName.self
, just not apparent as it's passed implicitly.
You can confirm this behavior of self
in a static
function, and furthermore even observe how self
behaves in a normal function in the following example:
class ClassName {
static func check() {
print("static function check")
print(type(of: self)) //ClassName.Type
//same as
print(type(of: ClassName.self)) //ClassName.Type
//test
print(type(of: self) == type(of: ClassName.self)) //true
}
func check() {
print("normal function check")
print(type(of: self)) //ClassName
//test
print(type(of: self) == type(of: ClassName.self)) //false
}
}
ClassName.check()
ClassName().check()
Also shows us that normal functions access self
as ClassName
which is an instance type, similar to variables.
Bundle(for:)
takes an object typeself
as ClassName
which is an instance typeself
as ClassName
which is an instance typeself
as ClassName.Type
which is an Object type, as it's passed implicitly to the functionUpvotes: 1
Reputation: 54745
You can simply use the class name instead of self
.
You also shouldn't be using NSDictionary
and then casting to a Swift Dictionary
. Use PropertyListDecoder
instead.
class MyClass {
static let myDic = try! PropertyListDecoder().decode([String:String].self, from: try! Data(contentsOf: Bundle(for: MyClass.self).url(forResource: "filename", withExtension: "plist")))
}
Upvotes: 1
Reputation: 100533
You can do
class MyClass {
static var myDic: [String: String] = NSDictionary(contentsOfFile: Bundle(for:MyClass.self).path(forResource: "filename", ofType: "plist")!) as! [String: String]
}
As you can't access self
inside a static variable , or use the bundle identifier
class MyClass {
static var myDic: [String: String] = NSDictionary(contentsOfFile: Bundle(identifier: "comThisBundle")!.path(forResource: "filename", ofType: "plist")!) as! [String: String]
}
Upvotes: 1