#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()
принимает строку. Эти типы соответствуют тем, которые указаны в моем списке.