簡體   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

我是來自Android背景的iOS初學者,並且剛剛了解了表視圖(對我來說,這是一個Android ListView)。 我正在嘗試從視圖控制器中分離數據源和委托。 我找到了一些有關如何執行此操作的教程,但仍堅持弄清楚如何將單擊的項目發送到另一個視圖控制器。 代碼如下:

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){ } 由於PicturesDataSource類中沒有“ storyboard”和“ navigationController”,如何將單擊的項目(圖片名稱)發送到DetailsViewController

有關於分離數據源和委托的StackOverflow答案,但沒有解決我的問題。

使用:Xcode 8.3 beta 6

您可以在表視圖事件處理程序中包含對主視圖控制器的引用。 以下是我從您的示例中得出的游樂場代碼:

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)
    }
  }
}

使用此方法可以獲取StoryBoard對象

let storyboard : UIStoryboard = UIStoryboard(name: "Main", bundle: nil)

現在,您的第二個問題是關於如何獲取導航控制器的。 這意味着在您的情況下如何獲取currentViewController 這可以通過下面的代碼獲得

 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
    }

現在您的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)  
}

您正在嘗試遵守MVC,但是您卻混淆了實際的數據源。

PicturesDataSource不是您的數據源 它是告訴您表如何設置自身的代碼。

PictureModelsDataController()是從中獲取實際填充該表的數據的源。


您發布的所有代碼都應在同一類中:

class PictureTableViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {

更改這些行:

pictureTableView.dataSource = picsDataSource
pictureTableView.delegate = picsDataSource

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

並刪除:

private let picsDataSource: PicturesDataSource

required init?(coder aDecoder: NSCoder) {
    self.picsDataSource = PicturesDataSource()
    super.init(coder: aDecoder)
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM