在静态上下文中引用“自我”

时间:2019-02-19 11:06:58

标签: ios swift class

我在这里了解为什么我实施的解决方案不起作用。基本上,我有一个名为MyClass的类,并且在该类中,我希望有一个从plist文件创建的静态字典。像这样:

class MyClass {        
    static var myDic: [String: String] = NSDictionary(contentsOfFile: Bundle(for: self).path(forResource: "filename", ofType: "plist")!) as! [String: String]    
}

如果这样做,编译器会抱怨:

Cannot convert value of type '(MyClass) -> () -> (MyClass)' to expected argument type 'AnyClass' (aka 'AnyObject.Type')

但是如果我更改myDic var并创建一个返回该dic的静态方法,那一切都很好:

class MyClass {
    static func myDic() -> [String: String] {
        return NSDictionary(contentsOfFile: Bundle(for: self).path(forResource: "PlayerRolesWithColors", ofType: "plist")!) as! [String: String]
    }
}

这里有两个问题:

  1. 此sintax在编译器错误中意味着什么? '(MyClass) -> () -> (MyClass)'
  2. 这两种情况有什么区别?为什么前者不能工作而后者很好呢?

谢谢。

3 个答案:

答案 0 :(得分:1)

你可以

class MyClass {
    static var myDic: [String: String] = NSDictionary(contentsOfFile: Bundle(for:MyClass.self).path(forResource: "filename", ofType: "plist")!) as! [String: String]
}

由于您无法在静态变量内访问self或使用包标识符

class MyClass {
    static var myDic: [String: String] = NSDictionary(contentsOfFile: Bundle(identifier: "comThisBundle")!.path(forResource: "filename", ofType: "plist")!) as! [String: String]
}

答案 1 :(得分:1)

您可以简单地使用类名代替self

您也不应该使用NSDictionary然后转换为Swift Dictionary。请改用PropertyListDecoder

class MyClass {
    static let myDic = try! PropertyListDecoder().decode([String:String].self, from: try! Data(contentsOf: Bundle(for: MyClass.self).url(forResource: "filename", withExtension: "plist")))
}

答案 2 :(得分:1)

让我们看一个更简单(有效)的示例,让您的核心问题保持不变:

class ClassName {
    static var bundle = Bundle(for: ClassName.self)

    static func getBundle() -> Bundle {
        return Bundle(for: self)
    }
}

首先,请注意Bundle(for: AnyClass)采用的是对象类型。


1。关于变量

顶级变量将self作为实例类型ClassName访问,而不管它是否声明为let / var / lazy /计算的还是静态的。

所以:

static var bundle = Bundle(for: self)

与:

static var bundle = Bundle(for: ClassName())

两者均无效,并产生以下错误:

  

无法将类型“ ClassName”的值转换为预期的参数类型“ AnyClass”(又名“ AnyObject.Type”)

可以肯定的是,这是因为我们传递的是实例类型,而不是预期的Object类型。

解决方案:

static var bundle = Bundle(for: ClassName.self)

2。关于静态函数

对于静态函数,这有点不同。

  

调用静态方法的元类型在您的方法中可以作为self使用(简单地作为隐式参数传递)。

     

参考:https://stackoverflow.com/a/42260880/2857130

在我的示例中,我们有:

static func getBundle() -> Bundle {
    return Bundle(for: self)
}

调用ClassName.getBundle()时,ClassName.Type被隐式传递给该函数。
现在,在静态函数中,self的类型为ClassName.Type,它是一种对象类型,可以直接在Bundle(for:)或接受对象类型作为参数的类似函数中应用。

因此,静态函数以self的身份访问ClassName.Type,这与ClassName.self相同,只是因为隐式传递而看不见。

您可以在self函数中确认static的这种行为,并在以下示例中甚至观察self在正常函数中的行为:

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()

还向我们展示了普通函数将self作为ClassName的实例类型来访问Bundle(for:)


摘要:

  • self采用对象类型
  • 顶级变量,以ClassName的身份访问self,这是实例类型
  • 普通函数以ClassName的身份访问self,这是实例类型
  • 静态函数以ClassName.Type的身份访问http://cre.cit.api.here.com/2/calculateroute.json?app_id=xxxx&app_code=xxxx&mode=fastest;truck;traffic:disabled&driver_cost=10&waypoint0=55.308989,10.805059&waypoint1=55.368920,11.288338&attributes=ROAD_GEOM_FCn(BRIDGE) ,这是一种对象类型,因为它隐式传递给了函数