Search code examples
iosswiftuitableviewcloudkit

Pass data between tableViews by using storyboard instantiateviewcontrollerwithidentifier


I'm trying to pass data from one tableView to to a static one. I'm not using a segue and using instantiateviewcontrollerwithidentifier instead, i dont know where i'm going wrong here. I'm using cloudkit and fetching ckRecords from icloud. i have a collectionView first where i tap a cell and displays books corresponding to that cell. However when they are displayed in the cells, i want to tap on the cell to bring up the detailViewController. It's not working at the moment and can't get the head around why.

import CloudKit

class DetailViewController: UITableViewController {

    @IBOutlet weak var aboutBookLabel: UILabel!
    @IBOutlet weak var bookLengthLabel: UILabel!
    @IBOutlet weak var amazonPriceLabel: UILabel!
    @IBOutlet weak var ebayPriceLabel: UILabel!
    @IBOutlet weak var websitePriceLabel: UILabel!
    @IBOutlet weak var authorLabel: UILabel!
    @IBOutlet weak var bookTitleLabel: UILabel!
    @IBOutlet weak var bookImageView: UIImageView!

    var bookRecord: CKRecord?

    override func viewDidLoad() {
        super.viewDidLoad()
        populateData()
    }


    override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
        return UITableViewAutomaticDimension
    }

    override func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
        cell.backgroundColor = UIColor(red: 27.0/255.0, green: 28.0/255.0 , blue: 32.0/255.0, alpha: 1.0)
    }

    override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        tableView.deselectRow(at: indexPath, animated: true)
    }

    func populateData() {
        aboutBookLabel.text = bookRecord?.object(forKey: "description") as? String
        bookLengthLabel.text = bookRecord?.object(forKey: "length") as? String
        amazonPriceLabel.text = bookRecord?.object(forKey: "amazon") as? String
        ebayPriceLabel.text = bookRecord?.object(forKey: "ebay") as? String
        websitePriceLabel.text = bookRecord?.object(forKey: "authorPrice") as? String
        authorLabel.text = bookRecord?.object(forKey: "author") as? String
        bookTitleLabel.text = bookRecord?.object(forKey: "name") as? String
        if let imageFile = bookRecord?.object(forKey: "image") as? CKAsset {
            bookImageView.image = UIImage(contentsOfFile: imageFile.fileURL.path)
        }

    }
}

class BooksViewController: UIViewController {

    @IBOutlet weak var tableView: UITableView!

    let cellIdentifier = "bookCell"

    var books = [CKRecord]()

    var sectorTitle = "language"

    override func viewDidLoad() {
        super.viewDidLoad()
        registerNib()
        fetchBooksFromCloud()
        configureTableView()
    }

    func fetchBooksFromCloud() {
        books = [CKRecord]()
        books.removeAll()
        tableView.reloadData()

        let cloudContainer = CKContainer.default()
        let publicDatabase = cloudContainer.publicCloudDatabase
        let predicate = buildBookPredicate()
        let query = CKQuery(recordType: "Book", predicate: predicate)
        query.sortDescriptors = [NSSortDescriptor(key: "creationDate", ascending: false)]

        let queryOperation = CKQueryOperation(query: query)
        queryOperation.desiredKeys = ["name", "author", "image", "format", "description", "length", "amazon", "ebay", "authorPrice"]
        queryOperation.queuePriority = .veryHigh
        queryOperation.resultsLimit = 25
        queryOperation.recordFetchedBlock = { (record) -> Void in
            self.books.append(record)
        }
        DispatchQueue.global(qos: .userInteractive).async {
            queryOperation.queryCompletionBlock = { (cursor, error) -> Void in
                if let error = error {
                    print("Download failed \(error.localizedDescription)")
                    return
                }

                print("Download Successful")

                OperationQueue.main.addOperation {
                    DispatchQueue.main.async {
                        self.tableView.reloadData()
                    }
                }
            }
        }

        queryOperation.qualityOfService = .userInteractive

        publicDatabase.add(queryOperation)
    }

    private func buildBookPredicate() -> NSPredicate {
        return NSPredicate(format:"self contains '\(sectorTitle)'")
    }

extension BooksViewController: UITableViewDelegate, UITableViewDataSource {

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return books.count
    }

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: cellIdentifier , for: indexPath) as! BookCell
        let book = books[indexPath.row]
        let bookName = book.object(forKey: "name") as? String
        let authorName = book.object(forKey: "author") as? String
        let image = book.object(forKey: "image") as? CKAsset
        let formatName = book.object(forKey: "format") as? String

        cell.nameLabel.text = bookName
        cell.authorLabel.text = authorName
        cell.formatLabel.text = formatName
        cell.bookImageName.image = UIImage(contentsOfFile: image!.fileURL.path)

        return cell
    }

    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        let record = books[indexPath.row]
        if let detailVC = storyboard?.instantiateViewController(withIdentifier: "DetailVC") as? DetailViewController {
            detailVC.bookRecord = record
            navigationController?.pushViewController(detailVC, animated: true)
        }
        tableView.deselectRow(at: indexPath, animated: true)
    }

Solution

  • The storyboard property of UIViewController represents the storyboard from which the view controller originated. If you want to load another view controller from the same storyboard you can use it.

    However, if you want to load the UIViewController from another storyboard you have to create the UIStoryboard instance first.

    You can do it like this.

    UIStoryboard(name: "YourStoryboardName", bundle: nil).instantiateViewController(withIdentifier: "DetailVC")