Быстрое чтение Plist и инициализация массивов как объектов для ключа

Я разрабатываю небольшое приложение на основе UITableView в Swift. Я начал с жесткого кодирования некоторых базовых массивов как таковых (включая объявление базового класса и объявление выхода UITableView:

import UIKit

class ScenesViewController: UITableViewController {

@IBOutlet var myTableView: UITableView

var sceneName = ["Scene 1", "Scene 2", "Scene 3", "Scene 4", "Scene 5"]
var sceneDetail = ["Hi", "Hello", "Bye", "My Bad", "Happy"]

Этот код находится внутри UITableViewController, выход которого подключен к UITableView. Я создал для этого plist под названием «Scenes.plist» и попытался заменить код. В Objective-C я бы сделал так:

NSString *path = [[NSBundle mainBundle] pathForResource:@"Scenes" ofType:@"plist"];

NSDictionary *dict = [[NSDictionary alloc] initWithContentsOfFile:path];
sceneName = [dict objectForKey:@"SceneName"];
sceneDetail = [dict objectForKey:@"SceneDetail"];

Я начал делать это в Swift следующим образом:

let path = NSBundle.mainBundle().pathForResource("Scenes", ofType:"plist")

let dict = NSDictionary(contentsOfFile:path)  // Error: 'ScenesViewController.Type' does not have a member named 'path'

Я искал в Интернете решение, но не смог его найти. Поэтому я выбрал следующий курс действий — «почти» однострочник:

let dict = NSDictionary(contentsOfFile: 
    NSBundle.mainBundle().pathForResource("Scenes", ofType:"plist"))

var sceneName = dict["SceneName"] // Error: 'ScenesViewController.Type' does not have a member named 'dict'

Теперь единственное решение, к которому я могу почти прибегнуть, - это разместить все это в одной строке для каждого массива:

var sceneName = NSDictionary(contentsOfFile: 
    NSBundle.mainBundle().pathForResource("Scenes", ofType:"plist").objectForKey("SceneName")
// Warning: Variable 'sceneName' inferred to have type 'AnyObject!', which may be unexpected
// Fix-It: Add an explicit type annotation to silence this warning (var sceneName: AnyObject! = ...)

Поэтому я добавил явную аннотацию типа только для того, чтобы узнать, что ошибок больше. Внутри функции cellForRowAtIndexPath::

override func tableView(tableView: UITableView?, cellForRowAtIndexPath indexPath: NSIndexPath?) -> UITableViewCell? {
    let cell: UITableViewCell = tableView!.dequeueReusableCellWithIdentifier("reuseIdentifier", forIndexPath: indexPath) as UITableViewCell

    // Configure the cell...

    cell.textLabel.text = sceneName[indexPath!.row] // Error: could not find member 'row'
    return cell
}

На самом деле есть две ошибки; Я не знаю, случайно ли это продублировано или нет. Следующие ошибки находятся в методе prepareForSegue:sender::

override func prepareForSegue(segue: UIStoryboardSegue?, sender: AnyObject?) {
    if segue?.identifier == "ShowDetails" {
        var detailVC: ScenesDetailViewController = segue!.destinationViewController as ScenesDetailViewController

        var myIndexPath: NSIndexPath = myTableView.indexPathForSelectedRow()

        var row: Int = myIndexPath.row

        detailVC.detailModal = [sceneDetail[row], sceneName[row]] // Error: Could not find an overload for 'subscript' that accepts the supplied arguments
    }
}

Опять две ошибки; однако я считаю, что это связано с тем, что используются sceneDetail и sceneName. Кажется, повсюду возникают ошибки при чтении и использовании plist в файлах, которых нет (или с которыми я не сталкивался) в Objective-C.


person virenabhyankar    schedule 13.06.2014    source источник
comment
свойства row и section элемента NSIndexPath определены в UIKit, а не в Foundation. Решит ли эту проблему добавление import UIKit в ваш файл?   -  person Jack    schedule 13.06.2014
comment
@JackWu UIKit уже импортирован; это первая линия   -  person virenabhyankar    schedule 14.06.2014


Ответы (2)


Чтобы решить вашу первоначальную проблему, поместите код внутри функции, например:

var memoryName = []
var memoryDetail = []

override func awakeFromNib() {
    super.awakeFromNib()

    let path = NSBundle.mainBundle().pathForResource("Memories", ofType:"plist")
    let dict = NSDictionary(contentsOfFile:path)

    memoryName = dict["MemoryName"] as Array<String>
    memoryDetail = dict["MemoryDetail"] as Array<String>
}
person paiv    schedule 13.06.2014

Вы можете решить эту проблему, переместив свой код в функцию, которая вызывается после инициализации ваших объектов.

Свойства инициализируются как часть инициализации вашего объекта. Вы создали path и dict как свойства и пытаетесь инициализировать их кодом, который не соответствует требованиям для инициализации.

Инициализатор не может вызывать какие-либо методы экземпляра, считывать значения каких-либо свойств экземпляра или ссылаться на себя как на значение до тех пор, пока не будет завершена первая фаза инициализации.

--Язык программирования Swift — Инициализация — Проверка безопасности 4

Кроме того, кажется, что вы хотите и нуждаетесь только в том, чтобы sceneName и sceneDetail были свойствами, поэтому вы можете полностью перемещать их в рамках метода, который вы используете для заполнения sceneDetail и sceneName после инициализация.

Мне трудно сказать, что такое ошибка нижнего индекса, точно, потому что я не вижу, какой тип данных должен содержать detailVC.detailModal; даже в этом случае кажется, что в массив detailModal передается неправильный тип объекта. Хорошее небольшое описание этой проблемы: Swift и массивы.

person timeSmith    schedule 15.08.2014