【问题标题】:Passing data between View Controllers in Swift (From TableView to DetailViewController)在 Swift 中的视图控制器之间传递数据(从 TableView 到 DetailViewController)
【发布时间】:2016-02-12 03:25:43
【问题描述】:

我有两个文件,MyTableViewController 和 myViewController。我在 MyTableVIewController 中的 TableCell 上设置 UIImageView。 myViewController 不包含任何内容。我创建了一个名为 ImageArray 的数组,其中包含一个图像数组。

我的目标是当我在 myTableViewController 中单击 TableCell 上的图像时,我希望单击的图像出现在 myViewController 中。还有一些关于图像旁边点击的图像的描述。我想使用 myViewController 让用户获取所选图像的详细信息。

override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
    let cell = self.tableView.dequeueReusableCellWithIdentifier("Cell") as! UITableViewCell
    var ImageView = cell.viewWithTag(1) as! UIImageView
    ImageView.image = UIImage(named: ImageArray[indexPath.row])
    ImageView.contentMode = .ScaleAspectFit

    var TextView = cell.viewWithTag(2) as! UILabel
    TextView.text = ImageArray[indexPath.row]
    return cell
}

override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
    performSegueWithIdentifier("next", sender: indexPath)
}

override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
    if (segue.identifier == "next") {
        let destination = segue.destinationViewController as! myViewController
    }
}

我不知道该怎么做才能实现它。如果你能帮我弄清楚,我真的很感激!谢谢!

【问题讨论】:

    标签: ios swift uiviewcontroller tableview segue


    【解决方案1】:

    这应该会有所帮助:

    override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
        if (segue.identifier == "next") {
            let destination = segue.destinationViewController as! myViewController
            destination.imageView.image = UIImage(named: ImageArray[tableView.indexPathForSelectedRow?.row])
            destination.textView.text = ImageArray[tableView.indexPathForSelectedRow?.row]
        }
    

    }

    (其中 imageView 和 textView 是新 viewController 中的视图。)

    注意:

    1. tableView.indexPathForSelectedRow?.row 应该给你选择的行,顾名思义,但它可以是nil,所以要小心。
    2. 另外,Swift 变量命名约定是驼峰式,所以imageView 是正确的方式,而ImageView 是不正确的方式。

    【讨论】:

    • 感谢您的帮助!但是,尽管我写得完全正确,但它似乎不起作用。我收到的 [tableView.indexPathForSelectedRow?.row] 最后两行代码的错误是“无法使用 'NSIndexPath?' 类型的索引来下标 '[(String)]' 类型的值。我该如何解决这些错误?提前致谢!
    • 您介意包括如何初始化图像数组以及如何填充它,以便我知道如何访问它吗?
    【解决方案2】:

    首先,我假设您的 MyTableViewController 类同时符合 UITableViewDataSourceUITableViewDelegate 协议,并且您已经设置了 MyTableViewController类作为代码或故事板中的委托。

    整理后,有多种方法可以实现您所寻求的结果。 你可以在一个独立的类中声明你的 ImageArray 并在你的 MyTableViewController 类中调用它,使用 tableView 委托方法将它们索引到 tableView 上,最后使用 prepareForSegue 方法将图像推送到 myViewController。或者您可以简单地在 MyTableViewController 类的顶部声明和初始化您的 ImageArray,如下所示:

    var ImageArray = [("Moscow Russia.jpg", "Europe"),
        ("London England.jpg", "Europe")]  
    

    在上面的 ImageArray 中,确保您的图像名称与您导入 Xcode 项目的资产名称完全匹配。

    然后我们用下面需要的方法指定我们需要ImageArray在我们的tableView上占据多少行(即基本上将我们的ImageArray计入我们的TableView):

    func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int
    {
        return ImageArray.count ?? 0
    }
    

    接下来,您要使用 tableView:cellForRowAtIndexPath: 方法在单元格的每一行中显示您的 ImageArray

    关于您的 TableCell 的旁注:希望您的 TableCell 是 UITableViewCell 的子类,并且您已经声明并连接了两个 IBOutlet,例如 imageViewtextLabel em> 分别。此外,请确保您的 TableCell 正确链接到 Storyboard 中 Identity Inspector 下的原型单元格)您的 TableCell 类应如下所示:

    import UIKit
    class CustomTableViewCell: UITableViewCell {
    @IBOutlet weak var imageView: UIImageView!
    @IBOutlet weak var textLabel: UILabel!
    }
    

    现在回到你的 MyTableVIewController 类。从您的代码中,我看到您将“let cell = ...”这一行转换为“UITableViewCell.您应该将其转换为“TableCell”,因为您将其子类化。实现tableView:cellForRowAtIndexPath:方法如下:

    func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell
    {        
        let cell = self.tableView.dequeueReusableCellWithIdentifier("Cell") as! TableCell
    
    //Note that I'm using tuples here. Pretty cool huh. Got to love Swift!
      let (imageName, textNameToGoWithImage) = ImageArray[indexPath.row]
    
        cell.textLabel.text = textNameToGoWithImage
        cell.imageView.image = UIImage(named: imageName)
        cell.imageView.contentMode = .ScaleAspectFit
    
    // You could have also used 'if let' in optional binding to safely unwrap your image if you want like below.
       //    if let image = UIImage(named: imageName){
       //        cell.imageView?.image = image
      //         cell.imageView.contentMode = .ScaleAspectFit
      //     }
    
        return cell
    }
    

    您似乎对何时何地使用 performSegueWithIdentifier 方法而不是使用 -prepareForSegue 感到有些困惑 方法。甚至何时使用 tableView:didSelectRowAtIndexPath 方法

    让我在这里简单解释一下。当您没有将转场从一个 ViewController 的场景控制拖到 Storyboard 中的另一个场景时,您可以使用 performSegueWithIdentifier 方法。这样,只要您在 Storyboard 中的“属性检查器。'

    现在,如果您改用 Storyboard,则不需要 tableView:didSelectRowAtIndexPath 方法。 tableView:didSelectRowAtIndexPath 方法的作用是它告诉委托指定的行现在已被选中,我们可以在其代码主体中执行某些操作(例如推送图像或文本到另一个 ViewController 场景,就像你正在尝试做的那样)。但是当你使用 segues 时,这就变得多余了。您所要做的就是control-drag 上的表格单元格 segue MyTableViewController 场景到您的 myViewController 场景。选择“显示”并为 segue 指定一个 identifier 名称,就像你之前一样完成“下一个”。 (附注:如果您希望在运行应用程序时在顶部导航栏显示 Back 按钮功能,您只需嵌入您的MyTableViewControllerUINavigationController 中为您提供“Back”按钮功能。使用您的 MyTableViewController em> 在 Storyboard 中选择场景,转到顶部菜单并选择 Editor >> Embed In >> Navigation Controller。然后哇!!)

    现在让我们继续实现我们的 tableView:prepareForSegue 方法,如下所示:

     override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
        if segue.identifier == "next" {
            //Note that, originally, destinationViewController is of Type UIViewController and has to be casted as myViewController instead since that's the ViewController we trying to go to. 
            let destinationVC = segue.destinationViewController as! myViewController
    
    
            if let indexPath = self.tableView.indexPathForSelectedRow{
    
                let selectedRow = ImageArray[indexPath.row]
    
                destinationVC.imageName2 = selectedRow.0
                destinationVC.textName2 = selectedRow.1
    }
    

    根据上面的代码,确保在 myViewControllerimageName' 和 'textName' 设置为 properties /em> 类,然后您可以使用现在类型为 myViewController 的 'destinationVC' 访问它们。这两个属性将保存我们从 MyTableViewController 类传递到 myViewController 类的数据。我们正在使用数组索引将数据相应地传递给这两个属性。

    然后,您可以创建两个 IBOutlet 来显示您的图像和文本,方法是将这些设置的“imageName2”和“textName2”属性传递给您的 outlet(或任何用于那件事)。

    • 现在你必须先设置属性的原因 myViewController 类,然后再将它们传递或传递(即传递给 UI 元素、闭包、另一个 VC 等)是,当您从 MyTableViewController 场景 segue 到你的下一个 ViewController 场景(即您的 myViewController 场景),iOS 尚未实例化 第二个场景还没有。所以你需要一个属性来保存数据 您正在尝试首先传递到您的第二个场景视图控制器,以便您可以 稍后在该类最终加载时使用它。

    所以你的 myViewController 类应该如下所示:

    import UIKit
    
    class myViewController : UIViewController {
    
       //Your two strings to initially hold onto the data 
      //being passed to myViewController class
    var imageName2 : String?
    var textName2 : String?
    
    @IBOutlet weak var detailImageView: UIImageView!
    @IBOutlet weak var detailTextNameLabel: UITextField!
    
    override func viewDidLoad() {
        super.viewDidLoad()
    
        detailTextNameLabel.text = textName2!
    
        if let image = UIImage(named: imageName2!) {
            self.detailImageView.image = image
        }
    }
    

    就是这样!

    在 Swift 中标注和约定的注意事项:

    • 以大写字母开始命名类(即类 ViewController() {})
    • 类和属性应该捕捉它们的含义 代表。我会建议你改变你的 MyTableViewController 和 'myViewController' 相应的类以反映它们的真实情况 意思或做(您可以使用“MainTableViewController”和“DetailViewController”。这样就可以了)。
    • 对属性和方法使用驼峰标记。 (我用了你的标签 在您的问题中提供,以免让您感到困惑)。

      享受吧!

    【讨论】:

    • 嗨!感谢您的详细解释,这对我有很大帮助!我会继续努力,希望我能进步很多!再次谢谢你!!! :)
    • 没问题。让我知道你的情况如何!祝你好运!
    【解决方案3】:

    在 swift 3 中,您可以执行以下操作:

    在您的MyTableViewController 班级中:

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
    {
        let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) as! UITableViewCell
    
        // for imageview
    
        var ImageView : UIImageView = cell.contentView.viewWithTag(1) as! UIImageView
        ImageView.image = UIImage(named: ImageArray[indexPath.row])
    
    
        // for text
    
        var TextView : UILabel = cell.contentView.viewWithTag(2) as! UILabel
        ImageView.text = ImageArray[indexPath.row]
    
        return cell
    }
    

    在你的didSelectRow 方法中:

    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath)
    {
       let nextVC = self.storyboard?.instantiateViewController(withIdentifier: "myViewController") as! myViewController
       nextVC.myImgView.image = UIImame(named: ImageArray[indexPath.row])
       nextVC.myLabel.text = ImageArray[indexPath.row]
       self.present(nextVC!, animated: true)
    }
    

    myViewController类中:

    class myViewController: UIViewController
    {
        let myImageView = UIImageView()
        let myLabel = UILabel()
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2014-08-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多