简体   繁体   English

当数据源和委托与View Controller分开时,如何将Table View的单击项发送到其他View Controller

[英]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.

相关问题 如何在View Controller外部设置数据源和委托 - How to set datasource and delegate Outside of View Controller 将数组从1个视图控制器发送到2个其他单独的视图控制器 - Send array from 1 view controller to 2 other separate view controllers 发送委托uitableview到其他视图控制器 - send delegate uitableview to other view controller 当视图控制器已经继承自基本视图控制器时,如何在视图控制器上创建表视图 - How to create a table view on a view controller when the view controller already inherits from a base view controller 将CollectionView委托和数据源带出视图控制器 - Take collectionview delegate and datasource out of view controller 与控制器分开的视图 - separate view from controller 使用推视控制器时如何将Uiimage从一个视图控制器传递到其他视图控制器? - How to Passing Uiimage from one view controller to Other view controller when using push view controller used? 如何将 NSURL 从委托传递给视图控制器 - How to pass NSURL to view controller from delegate 代表 SwiftUI 从托管视图 Controller 查看 - Delegate for SwiftUI View from Hosting View Controller 使用popvivew控制器时,如何将Uiimage从一个视图控制器传递到另一个视图控制器? - How to Passing Uiimage from one view controller to Other view controller when using popvivew controller used?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM