Swift 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. Изглежда навсякъде има грешки при четене и използване на plists във файлове, които не са там (или които не съм срещал) в 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