在 Swift 中的视图控制器之间传递数据(从 TableView 到 DetailViewController)
Passing data between View Controllers in Swift (From TableView to DetailViewController)
我有两个文件,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
}
}
我不知道该怎么做才能让它发生。如果你能帮我弄清楚,我真的很感激!谢谢!
这应该有帮助:
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
,所以要小心。
- 另外,Swift变量命名约定是驼峰式命名,所以
imageView
是正确的方式,而ImageView
是不正确的。
首先,我假设您的 MyTableViewController class 符合 UITableViewDataSource 和 UITableViewDelegate 协议,并且您已将 MyTableViewController class 设置为代码中的委托或通过情节提要。
经过整理,有多种方法可以达到您想要的结果。
您可以在独立的 class 中声明您的 ImageArray 并在您的 MyTableViewController class 中调用它,使用 tableView 委托方法将它们索引到 tableView,最后使用 prepareForSegue 方法将您的图像推送到您的 myViewController。或者您可以简单地在 MyTableViewController class 的顶部声明并初始化您的 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 子class编辑的,并且您已经声明并连接了两个 IBOutlet,比如说, imageView 和 textLabel 分别。此外,请确保您的 TableCell 已正确链接到 Storyboard 中 Identity Inspector 下的原型单元格)您的 TableCell class 应如下所示:
import UIKit
class CustomTableViewCell: UITableViewCell {
@IBOutlet weak var imageView: UIImageView!
@IBOutlet weak var textLabel: UILabel!
}
现在回到您的 MyTableVIewController class。从您的代码中,我看到您将行 'let cell = ...' 转换为 'UITableViewCell。您应该将其转换为 'TableCell',因为您正在对它进行子class。实现 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 方法而不是使用 -[=106 有点困惑=]prepareForSegue 方法。甚至什么时候使用 tableView:didSelectRowAtIndexPath 方法。
这里简单说明一下。当您没有控制拖动 segue 从一个 ViewController 的场景到情节提要中的另一个场景时,您可以使用 performSegueWithIdentifier 方法。这样,使用 performSegueWithIdentifier 方法将允许您在 ViewController 场景之间移动,只要您指定正确的标识符即可已在“Attributes Inspector.'
下的故事板中设置
现在,如果您改用 Storyboard,则不需要 tableView:didSelectRowAtIndexPath 方法。 tableView:didSelectRowAtIndexPath 方法的作用是告诉代理指定的行现在是 selected我们可以在它的代码体内做一些事情(比如将图像或文本推送到另一个 ViewController 场景,就像你想做的那样)。但是当你使用 segues 时,这就变得多余了。您所要做的就是 control-drag a segue 从 table cell 在你的 MyTableViewController 场景到你的 myViewController 场景。选择'Show'并给segue一个标识符 命名为“next”。 (一点旁注: 如果您希望 后退 按钮功能显示在顶部导航栏你 运行 你的应用程序,你只需将你的 MyTableViewController 嵌入 UINavigationController 给你'Back' 按钮功能。使用您的 MyTableViewController 场景 select在 Storyboard 中编辑,转到顶部菜单和 select Editor >> Embed In >> Navigation Controller。然后 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
}
从上面的代码中,确保将“imageName”和“textName”设置为 properties 在您的 myViewController class 中,然后您才能使用 'destinationVC' 现在是 myViewController 类型。这两个属性将保存我们从 MyTableViewController class 传递到 myViewController class。我们正在使用数组索引将数据相应地传递给这两个属性。
然后您可以创建两个 IBOutlets 来显示您的图像和文本,方法是将这些设置的“imageName2”和“textName2”属性传递给您的网点(或任何 UI 控件)。
- 现在您必须首先设置属性的原因是
myViewController class 在你传递它们之前或周围(即传递给
UI 元素、闭包、另一个 VC 等)是这样的,当您点击 tableView 单元格时
MyTableViewController 场景到 segue 到你的下一个 ViewController
场景(即您的 myViewController 场景),iOS 尚未实例化
第二个场景。所以你需要一个 属性 来保存数据
你试图首先传递到你的第二个场景视图控制器,这样你就可以
稍后在 class 最终加载时使用它。
所以你的 myViewController class 应该如下所示:
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中标签和约定的注意事项:
- 开始用正楷命名 classes(即 class
ViewController() {})
- 类 和属性应该捕捉它们的含义
代表。我建议您更改 MyTableViewController
并且“我的ViewController”class相应地反映了他们的真实情况
意思或做(你可以选择 'MainTableViewController' 和 'DetailViewController'。这样就可以了)。
对属性和方法使用 camelToe 标签。 (我用了你的标签
在您的问题中提供,以免让您感到困惑。
尽情享受吧!
在 swift 3 你可以这样做:
在你的 MyTableViewController
class:
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:
class myViewController: UIViewController
{
let myImageView = UIImageView()
let myLabel = UILabel()
}
我有两个文件,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
}
}
我不知道该怎么做才能让它发生。如果你能帮我弄清楚,我真的很感激!谢谢!
这应该有帮助:
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
,所以要小心。- 另外,Swift变量命名约定是驼峰式命名,所以
imageView
是正确的方式,而ImageView
是不正确的。
首先,我假设您的 MyTableViewController class 符合 UITableViewDataSource 和 UITableViewDelegate 协议,并且您已将 MyTableViewController class 设置为代码中的委托或通过情节提要。
经过整理,有多种方法可以达到您想要的结果。 您可以在独立的 class 中声明您的 ImageArray 并在您的 MyTableViewController class 中调用它,使用 tableView 委托方法将它们索引到 tableView,最后使用 prepareForSegue 方法将您的图像推送到您的 myViewController。或者您可以简单地在 MyTableViewController class 的顶部声明并初始化您的 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 子class编辑的,并且您已经声明并连接了两个 IBOutlet,比如说, imageView 和 textLabel 分别。此外,请确保您的 TableCell 已正确链接到 Storyboard 中 Identity Inspector 下的原型单元格)您的 TableCell class 应如下所示:
import UIKit
class CustomTableViewCell: UITableViewCell {
@IBOutlet weak var imageView: UIImageView!
@IBOutlet weak var textLabel: UILabel!
}
现在回到您的 MyTableVIewController class。从您的代码中,我看到您将行 'let cell = ...' 转换为 'UITableViewCell。您应该将其转换为 'TableCell',因为您正在对它进行子class。实现 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 方法而不是使用 -[=106 有点困惑=]prepareForSegue 方法。甚至什么时候使用 tableView:didSelectRowAtIndexPath 方法。
这里简单说明一下。当您没有控制拖动 segue 从一个 ViewController 的场景到情节提要中的另一个场景时,您可以使用 performSegueWithIdentifier 方法。这样,使用 performSegueWithIdentifier 方法将允许您在 ViewController 场景之间移动,只要您指定正确的标识符即可已在“Attributes Inspector.'
下的故事板中设置现在,如果您改用 Storyboard,则不需要 tableView:didSelectRowAtIndexPath 方法。 tableView:didSelectRowAtIndexPath 方法的作用是告诉代理指定的行现在是 selected我们可以在它的代码体内做一些事情(比如将图像或文本推送到另一个 ViewController 场景,就像你想做的那样)。但是当你使用 segues 时,这就变得多余了。您所要做的就是 control-drag a segue 从 table cell 在你的 MyTableViewController 场景到你的 myViewController 场景。选择'Show'并给segue一个标识符 命名为“next”。 (一点旁注: 如果您希望 后退 按钮功能显示在顶部导航栏你 运行 你的应用程序,你只需将你的 MyTableViewController 嵌入 UINavigationController 给你'Back' 按钮功能。使用您的 MyTableViewController 场景 select在 Storyboard 中编辑,转到顶部菜单和 select Editor >> Embed In >> Navigation Controller。然后 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
}
从上面的代码中,确保将“imageName”和“textName”设置为 properties 在您的 myViewController class 中,然后您才能使用 'destinationVC' 现在是 myViewController 类型。这两个属性将保存我们从 MyTableViewController class 传递到 myViewController class。我们正在使用数组索引将数据相应地传递给这两个属性。
然后您可以创建两个 IBOutlets 来显示您的图像和文本,方法是将这些设置的“imageName2”和“textName2”属性传递给您的网点(或任何 UI 控件)。
- 现在您必须首先设置属性的原因是 myViewController class 在你传递它们之前或周围(即传递给 UI 元素、闭包、另一个 VC 等)是这样的,当您点击 tableView 单元格时 MyTableViewController 场景到 segue 到你的下一个 ViewController 场景(即您的 myViewController 场景),iOS 尚未实例化 第二个场景。所以你需要一个 属性 来保存数据 你试图首先传递到你的第二个场景视图控制器,这样你就可以 稍后在 class 最终加载时使用它。
所以你的 myViewController class 应该如下所示:
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中标签和约定的注意事项:
- 开始用正楷命名 classes(即 class ViewController() {})
- 类 和属性应该捕捉它们的含义 代表。我建议您更改 MyTableViewController 并且“我的ViewController”class相应地反映了他们的真实情况 意思或做(你可以选择 'MainTableViewController' 和 'DetailViewController'。这样就可以了)。
对属性和方法使用 camelToe 标签。 (我用了你的标签 在您的问题中提供,以免让您感到困惑。
尽情享受吧!
在 swift 3 你可以这样做:
在你的 MyTableViewController
class:
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:
class myViewController: UIViewController
{
let myImageView = UIImageView()
let myLabel = UILabel()
}