使用 didSelectRowAtIndexPath 进行转场

Posted

技术标签:

【中文标题】使用 didSelectRowAtIndexPath 进行转场【英文标题】:Segue using didSelectRowAtIndexPath 【发布时间】:2015-03-01 18:01:37 【问题描述】:

我有一个核心数据项目的主从 VC 设置。如果searchBar 处于活动状态,则显示一组结果,如果未处于活动状态,则 fetchedResultsController 中的对象将显示在 MasterVC 中。

我一直在尝试使用 prepareForSegue 进行转场,但我的导师建议我使用 didSelectRowAtIndexPath 进行转场。

override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) 
    var selectedNote: Note

    // Check to see which table view cell was selected.
    if tableView == self.tableView 
        selectedNote = self.fetchedResultsController.objectAtIndexPath(indexPath) as! Note // <--this is "everything"
     else 
        // need this to unwrap the optional
        if let filteredObjects = filteredObjects 
            selectedNote = filteredObjects[indexPath.row]
        
    

    // Set up the detail view controller to show.
    let detailViewController = DetailViewController()
    detailViewController.detailDescriptionLabel = selectedNote.valueForKey("noteBody") as! UILabel

    // Note: Should not be necessary but current ios 8.0 bug requires it.
    tableView.deselectRowAtIndexPath(tableView.indexPathForSelectedRow()!, animated: false)

    // original code
    navigationController?.pushViewController(detailViewController, animated: true)


我收到此编译器错误:

Variable 'selectedNote' used before being initialized--在方法顶部声明!

如果我像这样在selectedNote 之前添加"self"

    detailViewController.detailDescriptionLabel = self.selectedNote.valueForKey("noteBody") as! UILabel

'MasterViewController' does not have a member named 'selectedNote' 尽管在那里。所以我显然在搞砸一些事情。

我在let detailViewController = DetailViewController()lldb 之前放置了一个断点,它打印出正确的对象。我在这里四处寻找解决方案,但我做不到。我在 GitHub 上找不到适用的代码。

class Note: NSManagedObject 

    @NSManaged var dateCreated: NSDate
    @NSManaged var dateEdited: NSDate
    @NSManaged var noteTitle: String
    @NSManaged var noteBody: String


任何想法如何将selectedNote 的属性转发给detailViewController

更新:

根据我得到的回复,我已经用这段代码关闭了编译器警告:

override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) 
    var selectedNote: Note?

    // Check to see which table view cell was selected.
    if tableView == self.tableView 
        selectedNote = self.fetchedResultsController.objectAtIndexPath(indexPath) as? Note // <--this is "everything"
     else 
        // need this to unwrap the optional
        if let filteredObjects = filteredObjects 
            selectedNote = filteredObjects[indexPath.row]
        
    

    // Set up the detail view controller to show.
    let detailViewController = DetailViewController()

    detailViewController.detailDescriptionLabel.text = (selectedNote!.valueForKey("noteBody") as! String)

    // Note: Should not be necessary but current iOS 8.0 bug requires it.
    tableView.deselectRowAtIndexPath(tableView.indexPathForSelectedRow()!, animated: false)

    // original code
    navigationController?.pushViewController(detailViewController, animated: true)


但是当它崩溃时,我在控制台中得到了这个: There are already notes in the app fatal error: unexpectedly found nil while unwrapping an Optional value

但是,当我键入 po selectedObject 时,我单击的对象会显示在控制台中。

【问题讨论】:

【参考方案1】:

您需要像这样将 selectedNote 声明为可选:

  var selectedNote: Note?

然后在使用之前检查值是否存在。

  if let note = selectedNote 
    // Set up the detail view controller to show.
    let detailViewController = DetailViewController()
    detailViewController.detailDescriptionLabel = note.valueForKey("noteBody") as! UILabel

    // Note: Should not be necessary but current iOS 8.0 bug requires it.
    tableView.deselectRowAtIndexPath(tableView.indexPathForSelectedRow()!, animated: false)            
    // original code
    navigationController?.pushViewController(detailViewController, animated: true)
  

更新

问题是您正在尝试创建 DetailViewController

let detailViewController = DetailViewController()

但是您需要的是引用 DetailViewController 以便将信息传递给它。

因此,您可以在 Interface builder 中创建从 Master 到 Detail 控制器的 segue。然后从 didSelectRowAtIndexPath

中删除逻辑
 override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) 

    // Note: Should not be necessary but current iOS 8.0 bug requires it.
    tableView.deselectRowAtIndexPath(tableView.indexPathForSelectedRow()!, animated: false)

并在prepareForSegue方法中实现:

override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) 

    if segue.identifier == "showDetail" 

        if let cell = sender as? UITableViewCell 

            let indexPath = tableView.indexPathForCell(cell)!

            var selectedNote: Note?

            if filteredObjects?.count > 0 
                selectedNote = filteredObjects![indexPath.row]
            else 
                selectedNote = self.fetchedResultsController.objectAtIndexPath(indexPath) as? Note // <--this is "everything"
            

            if let note = selectedNote 

                let controller = (segue.destinationViewController as! UINavigationController).topViewController as! DetailViewController
                controller.detailItem = note
            
        
    

showDetail - 您需要在 IB 中设置的 segue 标识符。 var detailItem: AnyObject? - 你需要在 DetailViewController 中声明它。

【讨论】:

这是一个小小的进步。现在我明白了:There are already notes in the app Could not cast value of type '__NSCFString' (0x10f759c90) to 'UILabel' (0x110b1b968). 我在lldb 上做了po selectedNote,它返回了我选择的注释,但它崩溃了 虽然这在技术上消除了编译器错误,但很有可能 selectedNote 没有被初始化,导致使用 selectedNote 时崩溃。您最好使用常规的可选... var selected注意:注意? Adrian,看看这段代码:selectedNote.valueForKey("noteBody") as! UIL标签。你确定 selectedNote 包含 UILabel 吗?我猜它包含您想要放入 detailDescriptionLabel 的文本。在这种情况下,您需要转换为 NSString 而不是 UILabel? 这是来自DetailVC的属性:@IBOutlet weak var detailDescriptionLabel: UILabel! 我不知道 Note 类的内部结构,但我猜你想写的内容如下:detailViewController.detailDescriptionLabel.text = note.valueForKey("noteBody") as! NSString.

以上是关于使用 didSelectRowAtIndexPath 进行转场的主要内容,如果未能解决你的问题,请参考以下文章

第一篇 用于测试使用

在使用加载数据流步骤的猪中,使用(使用 PigStorage)和不使用它有啥区别?

今目标使用教程 今目标任务使用篇

Qt静态编译时使用OpenSSL有三种方式(不使用,动态使用,静态使用,默认是动态使用)

MySQL db 在按日期排序时使用“使用位置;使用临时;使用文件排序”

使用“使用严格”作为“使用强”的备份