在Swift视图控制器之间传递数据(从TableView到DetailViewController)
我有两个文件,MyTableViewController和myViewController。 我在MyTableVIewController的TableCell上设置了UIImageView。 myViewController不包含任何东西。 我创build了一个名为ImageArray的数组,其中包含一个Images数组。
我打算在这里做的是当我点击myCableViewController中的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 } }
我不知道该怎么做才能做到这一点。 我真的很感激,如果你能帮我弄明白! 谢谢!
首先,我假设您的MyTableViewController类符合UITableViewDataSource和UITableViewDelegate协议,并且您已将MyTableViewController类设置为代码中的代理或Storyboard。
整理完成后,有多种方法可以实现您所寻求的结果。 你可以声明你的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的子类,你已经声明和连接了两个IBOutlets,分别是 imageView和textLabel 。 此外,确保您的TableCell正确链接到您的原型单元格中的情节板下的身份检查器 )您的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方法 。
让我在这里简单解释一下。 当你没有控制时,你可以使用performSegueWithIdentifier方法,从一个ViewController的场景中拖拽一个Segue到另一个Storyboard。 这样,使用performSegueWithIdentifier方法将允许您在ViewController场景之间移动,只要您在“ 属性检查器 ”下的Storyboard中指定了正确的标识符即可。 “
现在,如果您正在使用Storyboard,则不需要tableView:didSelectRowAtIndexPath方法。 tableView:didSelectRowAtIndexPath方法的作用是告诉委托,现在select了指定的行,并且我们可以在其代码体内执行某些操作(如将图像或文本推送到另一个ViewController Scene,就像你正在做的那样)。 但是,当你使用segues时,这变得多余。 所有你需要做的就是从你的MyTableViewController场景的表格单元格中 控制一个segue到你的myViewController场景。 select“ 显示 ”,并给你一个标识符名称,就像你已经完成“ 下一步 ”。 ( 有一点需要注意的是,如果你希望在运行应用程序时在顶部导航条上显示“ 返回 ”buttonfunction,只需将MyTableViewControllerembedded到UINavigationController中即可获得“ 返回 ”buttonfunction。在故事板中selectMyTableViewController场景,转到顶部菜单,select编辑器>>embedded>>导航控制器 ,然后walla !!)
现在让我们继续实现我们的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 }
从上面的代码中,请确保在myViewController类中首先将“ imageName ”和“ textName ”设置为属性 ,然后才能通过“ destinationVC ”(它现在是myViewControllertypes)访问它们。 这两个属性将把我们从MyTableViewController类传递到myViewController类的数据保存起来 。 我们正在使用数组索引来相应地将数据传递给这两个属性。
然后,您可以创build两个IBOutlet,通过将这些设置的“ imageName2 ”和“ textName2 ”属性传递给您的sockets(或任何用于该事项的UI控件)来显示图像和文本。
- 现在,为什么你必须在myViewController类中先设置属性,然后再传递它们(例如,到一个UI元素,闭包,另一个VC等),当你从MyTableViewController场景中击中tableView单元格,下一个ViewController场景(即你的myViewController场景),iOS还没有实例化第二个场景。 所以你需要一个属性来保存你想要传递给你的第二个场景View Controller的数据,以便以后在这个类最终加载时使用它。
所以你的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(){})
- 类和属性应该捕捉它们所代表的含义。 我会build议你相应地改变你的MyTableViewController和' myViewController '类,以反映他们真正的意思或做什么(你可以使用'MainTableViewController'和'DetailViewController',这将会很好)。
-
使用骆驼标签的属性和方法。 (我使用了你在问题中提供的标签,以免混淆太多)。
请享用!
这应该有助于:
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中的视图。)
注意:
-
tableView.indexPathForSelectedRow?.row
应该给你选定的行,顾名思义,但它可以nil
,所以要小心。 - 另外,Swiftvariables的命名约定是camelCase,所以
imageView
是正确的方法,而ImageView
是不正确的。
在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() }