如何在 UITableViewController 中正确使用 Realm 对象?

How to properly use Realm objects in a UITableViewController?

我正在尝试在我的 UITableViewController 中使用 Realm,如果我将对象转换为它的 class(如果我使用了错误的术语,请原谅我,我对 Swift、Realm ans iOS dev 还是很陌生!)...

我有一个 Site class 看起来像这样,数据库有几千个条目:

class Site: RLMObject {
    var id: String = ""
    var name: String = ""
}

在我的 table 视图控制器中,当我尝试根据其在结果集中的索引获取 Site 以加载到单元格中时,如果我尝试将其转换为 Site object 它总是 nil!如果我使用 AnyObject 设置它,那么我可以看到确实找到了该索引处的正确站点。

我猜测 AnyObject 上的 .name 调用之所以有效,是因为 AnyObject 响应了 .name,但它帮助我看到索引是正确的并且该站点确实存在...

override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
    let cell = self.tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as UITableViewCell
    let allSites = Site.allObjects()
    var any: AnyObject = allSites.objectAtIndex(UInt(indexPath.row))
    var site = allSites.objectAtIndex(UInt(indexPath.row)) as? Site
    println("With AnyObject: \(any.name)")
    println("With casting: \(site?.name)")

    return cell
}

上面打印语句的结果如下所示(例如在名为 'Addeboda' 的网站上):

With AnyObject: Addeboda
With casting: Optional("")

我是不是做错了什么?我在谷歌上搜索了一下,我能找到的所有教程和答案都是类似的,表明 results.objectAtIndex(index) as Class 应该是正确的方法。

无需强制转换

似乎不​​需要投射到站点。这很好用:

override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
    let cell = self.tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as UITableViewCell
    let allSites = Site.allObjects()
    let site: AnyObject! = allSites[UInt(indexPath.row)]

    cell.textLabel!.text = site.name

    println("Site is: \(site.id)")

    return cell
}

似乎是 Swift 或 Realm 的错误。我猜其中一个人在将 AnyObject! 向下转换为某物时会感到困惑。

正在用正确的类型初始化新实例

但是,如果您确实需要使用 Site 模型 class 您可以从结果中初始化一个新的 RLMObject

override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
    let cell = self.tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as UITableViewCell
    let allSites = Site.allObjects()
    let site = Site(object: allSites[UInt(indexPath.row)])

    cell.textLabel!.text = site.name

    println("Site is: \(site.id)")

    return cell
}

第一次尝试

很遗憾得知您在使用 Realm 和 Swift 时遇到问题。我绝不是 Swift 专业人士,但看起来您正在将 site 强制转换为可选,并且使用可选强制转换运算符 site?.name 的结果也是可选的。因此得到 Optional("").

你能试试看你在以下方面是否有更好的运气吗?

func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
    let cell = self.tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as UITableViewCell
    let allSites = Site.allObjects()

    if var site = allSites[UInt(indexPath.row)] as? Site {
        println("Site is: \(site.name)")
    } else {
        println("it not castable to Site. It is: \(toString(allSites[UInt(indexPath.row)].dynamicType))")
    }

    return cell
}

此外,您可以使用 yourObject.dynamicType 获取对对象真实 class 类型的引用。

祝你好运

这是 tableview sample project 中的一些代码:

class TableViewController: UITableViewController {

    var array = DemoObject.allObjects().sortedResultsUsingProperty("date", ascending: true)
    ...

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

        let object = array[UInt(indexPath.row)] as DemoObject
        cell.textLabel?.text = object.title
        cell.detailTextLabel?.text = object.date.description

        return cell
    }
}

您应该能够在存储该 indexPath.row 对象的行上进行转换