[英]How to send clicked item of Table View to other view controller when datasource and delegate are separate from View Controller
I am a beginner to iOS coming from the android background and just learned about table view (for me it's an Android ListView). 我是来自Android背景的iOS初学者,并且刚刚了解了表视图(对我来说,这是一个Android ListView)。 I am trying to separate data source & delegate from view controller.
我正在尝试从视图控制器中分离数据源和委托。 I found some tutorials on how to do so but stuck at figuring out how to send the clicked item to another view controller.
我找到了一些有关如何执行此操作的教程,但仍坚持弄清楚如何将单击的项目发送到另一个视图控制器。 The code is below:
代码如下:
class PictureTableViewController: UIViewController {
@IBOutlet weak var pictureTableView: UITableView!
private let picsDataSource: PicturesDataSource
required init?(coder aDecoder: NSCoder) {
self.picsDataSource = PicturesDataSource()
super.init(coder: aDecoder)
}
override func viewDidLoad() {
super.viewDidLoad()
pictureTableView.dataSource = picsDataSource
pictureTableView.reloadData()
pictureTableView.delegate = picsDataSource
}
}
class PicturesDataSource: NSObject, UITableViewDataSource, UITableViewDelegate{
private var pictureModels = [PictureModel]()
override init(){
let picModelsDataController = PictureModelsDataController()
pictureModels = picModelsDataController.pictureModels
}
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return pictureModels.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: String(describing: PictureCell.self)) as! PictureCell
let picModel = pictureModels[indexPath.row]
cell.pictureName = picModel.pictureName
cell.imageItem = picModel.imageItem
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
//1 - try loading the "Detail" view controller and typecasting it to be DetailViewController
if let detailViewController = storyboard.instantiateViewController(withIdentifier: "PictureDetailView") as? PictureDetailViewController {
//2 - success! set its selecteImage property
detailViewController.selectedImgName = pictureModels[indexPath.row].pictureName
//3 - now push it onto the navigation controller
navigationController?.pushViewController(detailViewController, animated: true)
}
}
}
Error in: func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath){ }
. Error in: func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath){ }
。 since "storyboard" & "navigationController" are not available in PicturesDataSource class, how can I send clicked item(picture name) to the DetailsViewController 由于PicturesDataSource类中没有“ storyboard”和“ navigationController”,如何将单击的项目(图片名称)发送到DetailsViewController
There are StackOverflow answers about separating data source and delegate but did not solve my problem. 有关于分离数据源和委托的StackOverflow答案,但没有解决我的问题。
Using: Xcode 8.3 beta 6
使用:Xcode 8.3 beta 6
You can include a reference to main view controller at your table view events handler. 您可以在表视图事件处理程序中包含对主视图控制器的引用。 Below is a playground code I derived from your example:
以下是我从您的示例中得出的游乐场代码:
import UIKit
// MARK: - Model
struct Picture {
let title: String
let image: UIImage
}
struct PictureModelsDataSource {
let pictures = [
Picture(title: "exampleTitle", image: UIImage(named: "exampleImage")!),
Picture(title: "exampleTitle", image: UIImage(named: "exampleImage")!)
]
}
// MARK - View
class PictureCell: UITableViewCell {
@IBOutlet weak var pictureTitleLabel: UILabel!
@IBOutlet weak var pictureImage: UIImageView!
}
// MARK: - Controller
class PictureTableViewController: UIViewController {
// MARK: - Properties
@IBOutlet weak var pictureTableView: UITableView!
private var pictureListController: PictureListController?
// MARK: - View lifecycle
override func viewDidLoad() {
super.viewDidLoad()
pictureListController = PictureListController()
pictureListController?.viewController = self
pictureTableView.dataSource = pictureListController
pictureTableView.delegate = pictureListController
pictureTableView.reloadData()
}
}
class PictureDetailViewController: UIViewController {
var selectedPictureTitle: String?
}
class PictureListController: NSObject, UITableViewDataSource, UITableViewDelegate {
// MARK: - Properties
weak var viewController: PictureTableViewController?
private let pictures: [Picture] = {
let pictureModelsDataSource = PictureModelsDataSource()
return pictureModelsDataSource.pictures
}()
// MARK: - View setup
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
// MARK: - Event handling
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return pictures.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
guard let cell = tableView.dequeueReusableCell(withIdentifier: String(describing: PictureCell.self)) as? PictureCell else {
return UITableViewCell()
}
let picture = pictures[indexPath.row]
cell.pictureTitleLabel.text = picture.title
cell.pictureImage.image = picture.image
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let pictureTitle = pictures[indexPath.row].title
let storyboard = UIStoryboard(name: "exampleStoryboard", bundle: nil)
if let pictureDetailViewController = storyboard.instantiateViewController(withIdentifier: "PictureDetailView") as? PictureDetailViewController {
pictureDetailViewController.selectedPictureTitle = pictureTitle
viewController?.navigationController?.pushViewController(pictureDetailViewController, animated: true)
}
}
}
See StoryBoard
object can be obtained by using this 使用此方法可以获取
StoryBoard
对象
let storyboard : UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
Now your second question is about how to get navigation controller. 现在,您的第二个问题是关于如何获取导航控制器的。 It means how to get
currentViewController
in your case. 这意味着在您的情况下如何获取
currentViewController
。 This can be get by below code 这可以通过下面的代码获得
func getCurrentViewController() -> UIViewController? {
if let rootController = UIApplication.shared.keyWindow?.rootViewController {
var currentController: UIViewController! = rootController
while( currentController.presentedViewController != nil ) {
currentController = currentController.presentedViewController
}
return currentController
}
return nil
}
Now your didSelectRowAt
code will look like this 现在您的
didSelectRowAt
代码将如下所示
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let storyboard : UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
if let detailViewController = storyboard.instantiateViewController(withIdentifier: "PictureDetailView") as? PictureDetailViewController
detailViewController.selectedImgName = pictureModels[indexPath.row].pictureName
self.getCurrentViewController()!.pushViewController(detailViewController, animated: true)
}
You are trying to adhere to MVC, but you are confusing what your actual data source is. 您正在尝试遵守MVC,但是您却混淆了实际的数据源。
PicturesDataSource
is not your data source . PicturesDataSource
不是您的数据源 。 It's the code that tells your table how to set itself up. 它是告诉您表如何设置自身的代码。
PictureModelsDataController()
is the source from which you get the data that actually populates that table. PictureModelsDataController()
是从中获取实际填充该表的数据的源。
All of your posted code should be in the same class: 您发布的所有代码都应在同一类中:
class PictureTableViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
Change these lines: 更改这些行:
pictureTableView.dataSource = picsDataSource
pictureTableView.delegate = picsDataSource
to 至
pictureTableView.dataSource = self // Note use of self because this is now the dataSource, not another class
pictureTableView.delegate = self // Note use of self because this is now the delegate, not another class
and remove: 并删除:
private let picsDataSource: PicturesDataSource
required init?(coder aDecoder: NSCoder) {
self.picsDataSource = PicturesDataSource()
super.init(coder: aDecoder)
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.