0

I want to use a TableView for the detail side of a Master Detail app. I have started with the standard Master Detail project in Xcode, deleted the standard app that comes with it, deleted the standard UIView detail controller, added a TableView controller, added a TextView to the prototype cell for testing, and created a new segue to the new TableView. I subclassed UITableViewCell and created an outlet (detailTextView) from the TextView to the subclass (TableViewCell). Changed the class in DetailViewController.swift from UIViewController to UITableViewController. I am successfully passing a string stringForTextView = "String for TextView" from master to the detail. But I can't figure out how to display that string in the TextView. I tried to reference the TextView text in the detail view through the outlet (detailTextView.text) but got "Use of unresolved identifier detailTextView"

Any help will be greatly appreciated.

Relevant code is shown below.

You can also download the whole project here if that would be helpful: http://greendept.com/MasterDetailTwoTableViews/

TableViewCell.swift (subclass for prototype cell in detail)

import UIKit

class TableViewCell: UITableViewCell {

    @IBOutlet weak var detailTextView: UITextView!

    override func awakeFromNib() {
        super.awakeFromNib()
        // Initialization code
    }

    override func setSelected(selected: Bool, animated: Bool) {
        super.setSelected(selected, animated: animated)

        // Configure the view for the selected state
    }

}

DetailViewController.swift

import UIKit

class DetailViewController: UITableViewController {

    var stringForTextView : String?

    var detailItem: AnyObject? {
        didSet {
            // Update the view.
            self.configureView()
        }
    }

    func configureView() {
        // THE NEXT TWO LINES WORK: PASSED IN STRING PRINTS TO CONSOLE
        let printThis = stringForTextView! as String
        print("\(printThis)")
        // BUT THE REFERENCE TO THE OUTLET BELOW DOES NOT WORK, GIVES
        // "Use of unresolved identifier detailTextView"
        detailTextView.text = printThis
        }

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
        self.configureView()
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }

}

MasterViewController.swift

import UIKit

class MasterViewController: UITableViewController {

    var detailViewController: DetailViewController? = nil

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.

        if let split = self.splitViewController {
            let controllers = split.viewControllers
            self.detailViewController = (controllers[controllers.count-1] as! UINavigationController).topViewController as? DetailViewController
        }
    }

    override func viewWillAppear(animated: Bool) {
        self.clearsSelectionOnViewWillAppear = self.splitViewController!.collapsed
        super.viewWillAppear(animated)
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }


    // MARK: - Segues

    override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
        if segue.identifier == "showDetail" {
            if let indexPath = self.tableView.indexPathForSelectedRow {
                let controller = (segue.destinationViewController as! UINavigationController).topViewController as! DetailViewController
                controller.stringForTextView = "String for TextView"
                controller.navigationItem.leftBarButtonItem = self.splitViewController?.displayModeButtonItem()
                controller.navigationItem.leftItemsSupplementBackButton = true
            }
        }
    }

    // MARK: - Table View

    override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
        return 1
    }

    override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return 1
    }

    override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath)
        return cell
    }

    override func tableView(tableView: UITableView, canEditRowAtIndexPath indexPath: NSIndexPath) -> Bool {
        // Return false if you do not want the specified item to be editable.
        return true
    }
}
user1147171
  • 1,033
  • 1
  • 13
  • 20
  • Why have you set your detail as a table view? A standard UIViewController subclass with a text view, text field or label would make more sense. If you use a table view then you will need to implement all of the tableview datasource methods in order to provide the cell – Paulw11 Jul 18 '16 at 05:10

2 Answers2

0

DetailViewController is a UITableViewController, and you can't access the detailTextView in the tableView controller. You defined the outlet in the cell, and that is where you can access and configure the detailTextView.

It doesn't make any sense to have the DetailViewController as a UITableViewController, if what you really want is to configure the text view there. Then you should set it back to a UIViewController, and add the text view as a single UITextView to the view controllers view.

Ivan C Myrvold
  • 498
  • 5
  • 15
  • Thanks. I thought that what I ultimately wanted to do in the detail view would work easier/better in a UITableViewController. That's why I was trying to do that. The TextView was just a start for testing/learning purposes. Maybe I'll play around with it a little more and see if there's any way I can do what I want working in the cell. – user1147171 Jul 18 '16 at 06:29
0

This link below shows how you can change text in a cell label even though the outlet to the textview is in the cell subclass. It shows this with a single TableView.

creating custom tableview cells in swift

In adapting the above approach for my test project, I didn't have to change the Master at all. In the Detail view, the configureView() doesn't do the main job of updating the TextView. That happens in cellForRowAtIndexPath -- second to the last function in detail view. Another difference is I could not, and did not need to, implement @IBOutlet var tableView: UITableView! -- because tableView was already available as a stored property. I also had to add overrride in a couple of places. Finally, in the TableViewCell class, I added an outlet linked to the content view of the TextView. The result is that the TextView text is getting updated.

TableViewCell.swift:

import UIKit   
class TableViewCell: UITableViewCell {

    @IBOutlet weak var detailTextView: UITextView!
    @IBOutlet weak var detailContentView: UIView!

    override func awakeFromNib() {
        super.awakeFromNib()
        // Initialization code
        print ("awakeFromNib")
    }

    override func setSelected(selected: Bool, animated: Bool) {
        super.setSelected(selected, animated: animated)

        // Configure the view for the selected state

        print("test")
    }
}

DetailViewController.swift:

import UIKit

class DetailViewController: UITableViewController {

    // @IBOutlet var tableView: UITableView! -- cannot override a stored property

    var stringForTextView : String?

    // Don't forget to enter this in IB also
    let cellReuseIdentifier = "reuseIdentifier"

    var detailItem: AnyObject? {
        didSet {
            // Update the view.
            self.configureView()
        }
    }

    func configureView() {
        // Update the user interface for the detail item.
            // stringForTextView
        let printThis = stringForTextView! as String
        print("\(printThis)")
 //       detailTextView.text = printThis
        }

    override func viewDidLoad() {
        super.viewDidLoad()
        tableView.delegate = self
        tableView.dataSource = self
        self.configureView()
    }

    // needed "override" here
    override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
      return 1
    }

    // create a cell for each table view row
    // needed "override" here
    override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {

        let cell:TableViewCell = self.tableView.dequeueReusableCellWithIdentifier(cellReuseIdentifier) as! TableViewCell

        cell.detailTextView.text = stringForTextView

        print("cell.detailTextView.text: \(cell.detailTextView.text)")

        print("row : \(indexPath.row)")

        return cell
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }
}
Community
  • 1
  • 1
user1147171
  • 1,033
  • 1
  • 13
  • 20
  • This approach is summarized well here: http://stackoverflow.com/questions/26561461/outlets-cannot-be-connected-to-repeating-content-ios "Create a table view cell subclass and set it as the class of the prototype. Add the outlets to that class and connect them. Now when you configure the cell you can access the outlets." – user1147171 Jul 19 '16 at 05:03