Обратитесь к «себе» в статическом контексте - PullRequest
0 голосов
/ 19 февраля 2019

Я здесь, чтобы понять, почему реализованное мной решение не будет работать.В основном у меня есть класс с именем 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. Что означает этот синтаксис в ошибке компилятора?'(MyClass) -> () -> (MyClass)'
  2. В чем разница между этими двумя случаями?Почему первый не работает, а второй хорошо?

Спасибо.

Ответы [ 3 ]

0 голосов
/ 19 февраля 2019

Вы можете просто использовать имя класса вместо 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")))
}
0 голосов
/ 19 февраля 2019

Давайте посмотрим на более простой (работающий) пример, в котором проблема с ядром не изменилась:

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

Конечно, это потому, что мы передаем тип экземпляра вместо ожидаемого типа объекта.

Решение:

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

2.Что касается статических функций

Что касается статической функции, то она немного отличается.

Метатип, для которого вы вызываете статический метод, доступен вам в методе как self(он просто передается как неявный параметр).

Ref: https://stackoverflow.com/a/42260880/2857130

В моем примере мы имеем:

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

Когда вы вызываете ClassName.getBundle(), ClassName.Type неявно передается функции.
Теперь внутри статической функции self имеет тип ClassName.Type, который является типом Object и может применяться непосредственно в * 1057.* или аналогичные функции, которые принимают тип объекта в качестве параметра.

Итак, статические функции обращаются к 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, что являетсяТип e, аналогичный переменным.


Резюме:

  • Bundle(for:) принимает тип объекта
  • Переменные на верхнем уровне, доступ selfкак ClassName, который является типом экземпляра
  • Доступ к обычным функциям self как ClassName, который является типом экземпляра
  • Доступ к статическим функциям self как ClassName.Type, который является объектомтип, поскольку он неявно передается в функцию
0 голосов
/ 19 февраля 2019

Вы можете сделать

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]
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...