Доступ к списку в Swift (ошибка: «Выражения не разрешены на верхнем уровне»)

#ios #xcode #swift #ios8

#iOS #xcode #swift #ios8

Вопрос:

У меня есть список, к которому я хотел бы получить доступ как к словарю Swift в Xcode. Я могу определить содержимое файла как NSDictionary, но каждый раз, когда я пытаюсь получить доступ к определенному значению / объекту из него, он показывает ошибку «Выражения не разрешены на верхнем уровне». Я пробовал использовать скобки, приведение типов и методы класса (с точечной нотацией) с использованием автозаполнения.

Мой список содержит словари, которые содержат словари, содержащие словари с CGFloats и строками.

Я хотел бы получить доступ к значениям экземпляра.

Вот код, который я использую для его определения, который находится в начале моей GameScene.swift (это игра SpriteKit):

 let levelBlocks = NSDictionary(contentsOfFile: NSBundle.mainBundle().pathForResource("LevelBlocks", ofType: "plist"))
  

Я хотел бы иметь возможность делать:

 levelBlocks["Level1"]
  

РЕДАКТИРОВАТЬ: добавлена дополнительная информация.

Я также попытался поместить его в viewDidLoad() , init() и использовать универсальный, который соответствует хэшируемому внутри функции вместо AnyObject / Any. Я все еще не могу получить доступ к строке.

РЕДАКТИРОВАНИЕ 2: я пробовал это в viewDidLoad(), он возвращает ошибку 254:

 let levelBlocks = NSDictionary(contentsOfFile: NSBundle.mainBundle().pathForResource("LevelBlocks", ofType: "plist")) as Dictionary<String, Dictionary<String, Dictionary<String, String>>>
let test = levelBlocks["Level1"] as Dictionary<String, Dictionary<String, String>>
let test1 = test["Block0"] as Dictionary<String, String>
let test2 = test1["color"] as String
println(test2)
  

Комментарии:

1. можем ли мы увидеть больше окружающего контекста? возможно, класс, в который вложен этот код?

Ответ №1:

Вот решение, которое я нашел:

 let levelBlocks = NSDictionary(contentsOfFile: NSBundle.mainBundle().pathForResource("LevelBlocks", ofType: "plist"))
let test: AnyObject = levelBlocks.objectForKey("Level1")
println(test) // Prints the value of test
  

Я установил тип test to AnyObject , чтобы отключить предупреждение о неожиданном выводе, который может произойти.

Кроме того, это должно быть сделано в методе класса.

Для доступа и сохранения определенного значения известного типа:

 let value = levelBlocks.objectForKey("Level1").objectForKey("amount") as Int
println(toString(value)) // Converts value to String and prints it
  

Ответ №2:

Xcode выдает эту ошибку, когда у вас есть выражение вне метода класса или экземпляра. Объявление глобальной переменной like levelBlocks — это нормально, но попытка вызвать методы для переменной (что и делает подписка) является выражением и не допускается там. Если вы просто тестируете вещи, вы можете создать другой глобальный:

 let levelBlocks = NSDictionary(contentsOfFile: NSBundle.mainBundle().pathForResource("LevelBlocks", ofType: "plist"))
let level1 = levelBlocks["level1"]
  

но на самом деле любые манипуляции должны происходить внутри вашего класса.

Примечание: это относится к файлам «.swift» — игровые площадки созданы только для такого рода неофициальных экспериментов. Работает ли ваш код на игровой площадке?


Вот разбивка файла Swift, который содержит класс с областью действия разных уровней, показанной в комментариях:

 // MyViewController.swift

let globalNumber = 10           // global scope: can be accessed from 
                                // anywhere in this module.

class MyViewController : ViewController {
    var instanceNumber = 5      // instance scope: instances of this class each
                                // maintain their own value. should be
                                // accessed within methods using self.varname

    override func viewDidLoad() {
        super.viewDidLoad()

        var localNumber = self.instanceNumber * globalNumber
                                // local scope: will disappear after this method
                                // finishes executing (in most cases)
    }
}
  

В вашем случае вы захотите загрузить список и получить доступ к его значениям внутри одного из ваших классов, возможно init ...DidLoad , метода or.

Что касается извлечения элементов из словаря, имейте в виду, что an NSDictionary соединяется напрямую с Swift как a Dictionary , поэтому вы можете загружать и анализировать его следующим образом:

 let path = NSBundle.mainBundle().pathForResource("LevelBlocks", ofType: "plist")
if let levelBlocks = NSDictionary(contentsOfFile: path) as? Dictionary<String, AnyObject> {
    let level1 = levelBlocks["level1"]                    // level1 is of type AnyObject?
    let level2 = levelBlocks["level2"] as NSString        // type NSString
    let level3: String = levelBlocks["level3"] as NSString     // type String
}
  

Комментарии:

1. Нет, он используется в файле с именем GameScene.swift.

2. Когда я пытаюсь сделать это в классе GameScene, который наследуется от SKScene и реализует протокол SKPhysicsContactDelegate, я получаю сообщение об ошибке «GameScene. Тип «не имеет члена с именем «levelBlocks»», даже если оба объекта объявлены как переменные и они не были объявлены вне класса.

3. С вашим кодом я получаю проблему с предложениями let level1: AnyObject! = levelBlocks["level1"] . Когда я печатаю let level1: NSDictionary = levelBlocks["level1"] , это подсказывает let level1: NSDictionary = levelBlocks["level1"] as NSDictionary . Есть ли способ преобразовать его в словарь Swift?

4. Эта вторая строка должна выполняться внутри метода экземпляра — вы не можете объявить свойство со значением, основанным на другом свойстве. Я добавил немного разъяснений.

5. Спасибо за ваш ответ. Он не работает с AnyObject, но весь код, кроме последней строки, работает в моем РЕДАКТИРОВАНИИ 2. Последняя строка должна работать, потому test2 что является строкой и println() принимает строку. Эти типы соответствуют тем, которые указаны в моем списке.