Custom Cell TextVIew text not changing - ios

I am creating a simple article application in IOS using Swift. I am having issues updating the text inside of my textview. but I have the textView in a custom TableViewCell class and cannot figure out how to change the text. I have also tried making a setter function. I have no error logs, I am printing the contents of the cell after I create it and after I change the text. When I create it it has place holder text, after i change it it IS changed in the cell in cellforRow, but physically displayed is the text from the xib.
import UIKit
class ViewController2: UIViewController, UITableViewDataSource, UITableViewDelegate, UITextViewDelegate {
//mydata
var articles = ["Article","Article","Article","Article","Article","Article","Article"]
var farmers = ["farmer","farmer","farmer","farmer","farmer","farmer","farmer",]
var products = ["coffee","coffee","coffee","coffee","coffee","coffee","coffee","coffee","coffee","coffee","coffee","coffee","coffee","coffee","coffee","coffee","coffee","coffee","coffee","coffee","coffee",]
var article = "I am aware that this question has been asked, but none of the answers have worked for me. I'm trying to implement a comments View controller, similar to what you can see in Instagram, where the size of the tableView cell depends on the size of the comment. So I though I would get the necessary height to display the whole comment in textView without scrolling, adjust the textView, then use it to set the heightForRowAtIndexPath appropriately, before finally reloading the table. However, I can't even get to resize the textView, I have tested a certain number of answers and still the textView won't budge."
//flags
var flag = 0 //0=article, 1 = categories, 2 = productpage
// outlets
#IBOutlet weak var tableView: UITableView!
///Default
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
let nib1 = UINib(nibName: "Picture2", bundle: nil)
tableView.registerNib(nib1, forCellReuseIdentifier: "Picture2")
let nib2 = UINib(nibName: "Title", bundle: nil)
tableView.registerNib(nib2, forCellReuseIdentifier: "Title")
let nib3 = UINib(nibName: "Article", bundle: nil)
tableView.registerNib(nib3, forCellReuseIdentifier: "Article")
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
//TableView
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
switch flag
{
case 0:
return 3
case 1:
return products.count
case 2:
return farmers.count
default:
return 1
}
}
func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
switch flag
{
case 0:
if(indexPath.row == 0)
{
return 216;
}
else if(indexPath.row == 1)
{
return 80;
}
else
{
var hieght = calculateHeightForString(article)
return hieght
}
case 1:
return 44
case 2:
return 216
default:
return 216
}
}
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
switch flag
{
case 0:
self.performSegueWithIdentifier("View2", sender: self)
case 1:
self.performSegueWithIdentifier("View2", sender: self)
case 2:
//self.performSegueWithIdentifier("Product", sender: self)
break
default:
return self.performSegueWithIdentifier("View2", sender: self)
}
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
switch flag
{
case 0:
if(indexPath.row == 0)
{
let cell = self.tableView.dequeueReusableCellWithIdentifier("Picture2", forIndexPath: indexPath) as! Picture2Cell
let imageName = "Bag.png"
let image = UIImage(named: imageName)
cell.Picture.image = image
return cell
}
else if(indexPath.row == 1)
{
let cell = self.tableView.dequeueReusableCellWithIdentifier("Title", forIndexPath: indexPath) as! TitleCell
cell.title.text = "THIS IS THE TTITLE"
cell.by.text = "Zach Chandler"
cell.country.text = "Camaroon"
return cell
}
else
{
var cell = self.tableView.dequeueReusableCellWithIdentifier("Article", forIndexPath: indexPath) as! ArticleCell
print(cell.textView.text)
println("Changed")
let currentText:NSString = article
cell.textView.text = currentText as String
print(cell.textView.text)
return cell
}
case 2:
let cell = self.tableView.dequeueReusableCellWithIdentifier("MainCell", forIndexPath: indexPath) as! Picture1Cell
cell.title.text = "indexpath.section \(indexPath.section)"
let imageName = "Bag.png"
let image = UIImage(named: imageName)
cell.picture.image = image
cell.subtitle.text = "indexPath.row \(indexPath.row)"
return cell
case 1:
let cell = self.tableView.dequeueReusableCellWithIdentifier("ProductCell", forIndexPath: indexPath) as! UITableViewCell
cell.textLabel!.text = products[indexPath.row]
let imageName = "bag.png"
let image = UIImage(named: imageName)
cell.imageView!.image = image
cell.detailTextLabel?.text = "indexpath.row\(indexPath.row)"
return cell
default:
let cell = self.tableView.dequeueReusableCellWithIdentifier("ProductCell", forIndexPath: indexPath) as!
UITableViewCell
cell.textLabel?.text = "indexpath.row\(indexPath.row)"
return cell
}
}
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
switch flag
{
case 0:
return 1
case 1:
return 1
case 2:
return farmers.count
default:
return 1
}
}
//segue
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
}
//personal functions
func calculateHeightForString(inString:String) -> CGFloat
{
var messageString = inString
var attributes = [UIFont(): UIFont.systemFontOfSize(15.0)]
var attrString:NSAttributedString? = NSAttributedString(string: messageString, attributes: attributes)
var rect:CGRect = attrString!.boundingRectWithSize(CGSizeMake(300.0,CGFloat.max), options: NSStringDrawingOptions.UsesLineFragmentOrigin, context:nil )
var requredSize:CGRect = rect
return requredSize.height //to include button's in your tableview
}
article class
import UIKit
class ArticleCell: UITableViewCell, UITextViewDelegate {
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
}
#IBOutlet weak var textView: UITextView!
override func setSelected(selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
func SetText(inString: String)
{
textView.text = inString
}

Try setting the delegate before you change the text, in your cellForRowAtIndexPath method. Should be something like
cell.textView.delegate = self

Related

Retrieving textfield data from custom cell from another view outside of the table view

I have a view with an embedded UITableViewController that is filled with custom cells. When I hit the save button I would like the getProjectName() within the UITableViewController to return the projectNameTF data within in the custom cell. Currently when I try to get the cell within the getProjectName() it returns a nil cell.
Main View:
class NewProjectView: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
}
#IBAction func saveBtn(_ sender: UIButton) {
print("Save button hit")
print(NewProjectTableViewController().getProjectName())
}
}
Embedded TableViewController
import UIKit
struct cellType{
var mainTitle = String()
var numOfChildCells = Int()
var opened = Bool()
}
class NewProjectTableViewController: UITableViewController {
var tableViewData = [cellType]()
var customCellData = [UITableViewCell]()
var projectNameTFR = UITextField()
// Counts the number of cells and displays them
override func numberOfSections(in tableView: UITableView) -> Int {
return tableViewData.count
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// If the parent cell is opened display the number of cells inside it
if tableViewData[section].opened == true {
return tableViewData[section].numOfChildCells + 1
}
else {
return 1
}
}
//
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
self.tableView.separatorStyle = .none
// Do this for the header cell
if indexPath.row == 0{
guard let cell = tableView.dequeueReusableCell(withIdentifier: "HeaderCell") as? HeaderCell else {return UITableViewCell()}
cell.backgroundColor = .clear
cell.setUpCell(title: tableViewData[indexPath.section].mainTitle)
// If cell should be opened, display correct open image
if tableViewData[indexPath.section].opened{
cell.openCell()
}
// else display closed image
else{
cell.closeCell()
}
return cell
// else it is a child cell
}else {
switch tableViewData[indexPath.section].mainTitle{
// Load Project info cell
case "Project Information":
guard let cell = tableView.dequeueReusableCell(withIdentifier: "ProjectNameCell") as? ProjectNameCell else {return UITableViewCell()}
projectNameTFR = cell.projectNameTF
return cell
case "Client Information":
guard let cell = tableView.dequeueReusableCell(withIdentifier: "ClientInfoCell") as? ClientInfoCell else {return UITableViewCell()}
return cell
default:
print("defaulted cell")
guard let cell = tableView.dequeueReusableCell(withIdentifier: "cell") else {return UITableViewCell()}
return cell
}
}
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if tableViewData[indexPath.section].opened == true{
tableViewData[indexPath.section].opened = false
let sections = IndexSet.init(integer: indexPath.section)
tableView.reloadSections(sections, with: .none)
let headerCell = tableView.cellForRow(at: indexPath) as! HeaderCell
}
else{
tableViewData[indexPath.section].opened = true
let sections = IndexSet.init(integer: indexPath.section)
tableView.reloadSections(sections, with: .none)
let headerCell = tableView.cellForRow(at: indexPath) as! HeaderCell
}
}
override func viewDidLoad() {
super.viewDidLoad()
//self.definesPresentationContext = true
tableView.delegate = self
tableView.dataSource = self
tableView.rowHeight = UITableView.automaticDimension
// Do any additional setup after loading the view.
print("add new client screen loaded")
registerTableViewCells()
// Create the cells
tableViewData = [cellType(mainTitle: "Project Information", numOfChildCells: 1, opened: true ),
cellType(mainTitle: "Client Information", numOfChildCells: 1, opened: false )]
}
override func viewWillAppear(_ animated: Bool) {
// Add a background view to the table view
let backgroundImage = UIImage(named: "App Background.png")
let imageView = UIImageView(image: backgroundImage)
self.tableView.backgroundView = imageView
}
override var preferredStatusBarStyle: UIStatusBarStyle {
return .lightContent
}
private func registerTableViewCells(){
let ClientInfoCell = UINib(nibName: "ClientInfoCell", bundle: nil)
self.tableView.register(ClientInfoCell, forCellReuseIdentifier: "ClientInfoCell")
let ProjectNameCell = UINib(nibName: "ProjectNameCell", bundle: nil)
self.tableView.register(ProjectNameCell, forCellReuseIdentifier: "ProjectNameCell")
let HeaderCell = UINib(nibName: "HeaderCell", bundle: nil)
self.tableView.register(HeaderCell, forCellReuseIdentifier: "HeaderCell")
let SaveCell = UINib(nibName: "SaveCell", bundle: nil)
self.tableView.register(SaveCell, forCellReuseIdentifier: "SaveCell")
}
func getProjectName() -> String{
let indexPath = NSIndexPath(row: 0, section: 0)
let cell = tableView?.cellForRow(at: indexPath as IndexPath) as? ProjectNameCell
print(type(of: cell))
if(cell==nil){
print("cell is nil")
}
return "I returned this test string"
}
}
Custom Cell I am trying to reach
import UIKit
class ProjectNameCell: UITableViewCell {
#IBOutlet weak var projectNameTF: UITextField!
var projectName = String()
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
backgroundColor = .clear
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
}
Well sir you are getting cell on index path 0 section number and 0th row
let indexPath = NSIndexPath(row: 0, section: 0)
on that index you have HeaderCell instead of ProjectNameCell thats why you are getting nil
this line can't cast your HeaderCell to ProjectNameCell
let cell = tableView?.cellForRow(at: indexPath as IndexPath) as? ProjectNameCell

How to show a parent view which is outside tableview and is scrollable?

I have a scenario where I need to show a parent view with shadow and corner radius containing a long list of reusable items. I used a tableView to display items. But I stuck at making my tableview expand as much as its contentSize. It works but not accurate. Any solutions?
Edit:
Desired result:
I used the following reference for self sizing tableview.
Self Sizing UITableView
I made a few modifications as below:
final class SelfSizedTableView: UITableView {
var maxHeight = CGFloat.greatestFiniteMagnitude
override func reloadData() {
super.reloadData()
self.invalidateIntrinsicContentSize()
self.layoutIfNeeded()
}
override var intrinsicContentSize: CGSize {
let height = min(contentSize.height, maxHeight)
let size = CGSize(width: contentSize.width, height: height)
return size
}
}
I used a parent tableView with a cell having my containerView and embedding this self sized tableView.
class MyContainerViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
// MARK: - IBOutlets
#IBOutlet weak var parentTableView: UITableView!
// MARK: - Life Cycle
override func viewDidLoad() {
super.viewDidLoad()
setupViews()
}
private func estimateDataHeight() -> CGFloat {
let detailCellHeight: CGFloat = 32
let headingCellHeight: CGFloat = 43
let headings: CGFloat = headingCellHeight*2
let detailsHeight: CGFloat = detailCellHeight*4
let baseHeight = headings + detailsHeight
let membersHeight =
CGFloat(sectionsArray.count) * detailCellHeight
return baseHeight + membersHeight
}
}
// MARK: - UITableViewDataSource
extension MyContainerViewController {
func tableView(_ tableView: UITableView,
numberOfRowsInSection section: Int) -> Int {
return 1
}
func tableView(_ tableView: UITableView,
cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let id = String(describing: MyContainerTVCell.self)
guard let cell = tableView
.dequeueReusableCell(withIdentifier: id, for: indexPath)
as? MyContainerTVCell else {
return UITableViewCell()
}
cell.policyDetails = dataSource
// my cheat/trick doesn't work on large data.
DispatchQueue.main.asyncAfter(deadline: .now()+0.4) {
tableView.beginUpdates()
cell.tableView.layoutIfNeeded()
cell.tableView.reloadData() // the overridden one
tableView.endUpdates()
}
return cell
}
}
extension MyContainerViewController {
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return UITableViewAutomaticDimension
}
func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
return estimateDataHeight()
}
}
My cell class which has the self size tableView and containerView:
class MyContainerTVCell: UITableViewCell, UITableViewDataSource, UITableViewDelegate {
// MARK: - IBOutlets
#IBOutlet weak var containerView: UIView!
#IBOutlet weak var shadowView: UIView!
#IBOutlet weak var tableView: SelfSizedTableView!
// MARK: - Properties
let titles = ["Email ID:", "Mobile Number:", "Address:", "ID: "] // first section data array
let moreData: [String] = [] // remaining reusable sections array
// no of subsequent sections for moreData array type
var numberOfSections: Int {
return 4
}
// MARK: -
var dataSource: MyDataSource!
// MARK: - Life Cycle
override func awakeFromNib() {
super.awakeFromNib()
setupView()
}
override func layoutSubviews() {
super.layoutSubviews()
}
// MARK: - Setup
func setupView() {
containerView.rounded(with: 10)
shadowView.layer.applyShadow()
tableView.dataSource = self
tableView.delegate = self
}
}
// MARK: - UITableViewDataSource
extension MyContainerTVCell {
func numberOfSections(in tableView: UITableView) -> Int {
return numberOfSections + 1
}
func tableView(_ tableView: UITableView,
numberOfRowsInSection section: Int) -> Int {
if section == 0 { return titles.count + 1 }
else if section == 1 { return moreData.count + 1 }
else { return moreData.count }
}
func tableView(_ tableView: UITableView,
cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let headerID = String(describing: MyHeaderTVCell.self)
let itemID = String(describing: MyItemTVCell.self)
switch indexPath.section {
case 0:
if indexPath.row == 0 {
guard let cell = tableView
.dequeueReusableCell(withIdentifier: headerID, for: indexPath)
as? MyHeaderTVCell else {
return UITableViewCell()
}
cell.titleLabel.text = dataSource.title
return cell
} else {
guard let cell = tableView
.dequeueReusableCell(withIdentifier: itemID, for: indexPath)
as? MyItemTVCell else {
return UITableViewCell()
}
let item = titles[indexPath.row-1]
cell.titleLabel.text = item
cell.separatorView.isHidden = true
let data: String
switch indexPath.row {
case 1:
data = dataSource.emailID
case 2:
data = dataSource.mobileNo
case 3:
data = dataSource.address
case 4:
data = dataSource.name
case 5:
data = dataSource.age
case 6:
data = dataSource.id
case 7:
data = dataSource.office
case 8:
data = dataSource.academic
default: data = String()
}
cell.detailLabel.text = data
return cell
}
case 1:
if indexPath.row == 0 {
guard let cell = tableView
.dequeueReusableCell(withIdentifier: headerID, for: indexPath)
as? MyHeaderTVCell else {
return UITableViewCell()
}
cell.titleLabel.text = "More Data"
return cell
} else {
guard let cell = tableView
.dequeueReusableCell(withIdentifier: itemID, for: indexPath)
as? MyItemTVCell else {
return UITableViewCell()
}
let sectionIndex = indexPath.section-1
guard sectionIndex <= numberOfSections-1,
let section = sectionsArray?[indexPath.section-1] else {
return UITableViewCell()
}
cell.titleLabel.text = moreData[indexPath.row-1]
cell.separatorView.isHidden = true
switch indexPath.row {
case 1:
cell.detailLabel.text = section.a
case 2:
cell.detailLabel.text = section.b
case 3:
cell.detailLabel.text = "\(section.c ?? 0)"
case 4:
cell.detailLabel.text = section.d
case 5:
cell.detailLabel.text = section.e
case 6:
cell.detailLabel.text = section.f
if indexPath.section < numberOfSections {
cell.separatorView.isHidden = false
}
default: break
}
return cell
}
default:
guard let cell = tableView
.dequeueReusableCell(withIdentifier: itemID, for: indexPath)
as? MyItemTVCell else {
return UITableViewCell()
}
let sectionIndex = indexPath.section-1
guard sectionIndex <= numberOfSections-1,
let section = sectionsArray?[indexPath.section-1] else {
return UITableViewCell()
}
cell.titleLabel.text = moreData[indexPath.row]
cell.separatorView.isHidden = true
switch indexPath.row {
case 0:
cell.detailLabel.text = section.a
case 1:
cell.detailLabel.text = section.b
case 2:
cell.detailLabel.text = "\(section.c ?? 0)"
case 3:
cell.detailLabel.text = section.d
case 4:
cell.detailLabel.text = section.e
case 5:
cell.detailLabel.text = section.f
if indexPath.section < numberOfSections {
cell.separatorView.isHidden = false
}
default: break
}
return cell
}
}
}
// MARK: - UITableViewDelegate
extension MyContainerTVCell {
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return UITableViewAutomaticDimension
}
func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
if indexPath.section == 0 && indexPath.row == 0 { return 43 }
if indexPath.section == 1 && indexPath.row == 0 { return 43 }
return 32
}
}
Why would you want to expand tableView as much as its content size to make it scrollable, when tableView is already scrollable?
However, if you have some other content, aside from table, on the screen and you want them to scroll together, then you need to embed all your content into UIScrollView.
Then, make a height constraint for you tableView in xib/storyboard with any value.
Then you might do something like this:
// in your view controller
private var heightObservation: NSKeyValueObservation?
// called once, for example, in viewDidLoad()
private func setupTableView() {
...
observation = tableView.constraintFrameHeightToContentSizeHeight()
}
extension UITableView {
func constraintFrameHeightToContentSizeHeight() -> NSKeyValueObservation {
return observe(\.contentSize, changeHandler: { (tableView, _) in
tableView.heightConstraint?.constant = tableView.contentSize.height
})
}
}
// find height constraint
extension UIView {
var heightConstraint: NSLayoutConstraint? {
return constraints.first(where: { $0.firstAttribute == .height })
}
}
Don't forget to uncheck "Scrolling Enabled" in xib/storyboard for that table view.

how to uncheck uitableview cells using accessory checkmark

i have two sections
1.MapViewController
2.TypesTableViewController
when i run my app and call TypesTableViewController and when it opens it shows all cells selected i want it to be unchecked
please help me and check my code
1.MapViewController
class MapViewController: UIViewController {
#IBOutlet weak var mapCenterPinImage: UIImageView!
#IBOutlet weak var pinImageVerticalConstraint: NSLayoutConstraint!
var searchedTypes = ["bakery", "bar", "cafe", "grocery_or_supermarket", "restaurant"]
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "Types Segue" {
let navigationController = segue.destinationViewController as! UINavigationController
let controller = navigationController.topViewController as! TypesTableViewController
controller.selectedTypes = searchedTypes
controller.delegate = self
}
}
}
// MARK: - TypesTableViewControllerDelegate
extension MapViewController: TypesTableViewControllerDelegate {
func typesController(controller: TypesTableViewController, didSelectTypes types: [String]) {
searchedTypes = controller.selectedTypes.sort()
dismissViewControllerAnimated(true, completion: nil)
}
}
2.TypesTableViewController
protocol TypesTableViewControllerDelegate: class {
func typesController(controller: TypesTableViewController, didSelectTypes types: [String])
}
class TypesTableViewController: UITableViewController {
let possibleTypesDictionary = ["bakery":"Bakery", "bar":"Bar", "cafe":"Cafe", "grocery_or_supermarket":"Supermarket", "restaurant":"Restaurant"]
var selectedTypes: [String]!
weak var delegate: TypesTableViewControllerDelegate!
var sortedKeys: [String] {
return possibleTypesDictionary.keys.sort()
}
// MARK: - Actions
#IBAction func donePressed(sender: AnyObject) {
delegate?.typesController(self, didSelectTypes: selectedTypes)
}
// MARK: - Table view data source
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return possibleTypesDictionary.count
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("TypeCell", forIndexPath: indexPath)
let key = sortedKeys[indexPath.row]
let type = possibleTypesDictionary[key]!
cell.textLabel?.text = type
cell.imageView?.image = UIImage(named: key)
cell.accessoryType = (selectedTypes!).contains(key) ? .Checkmark : .None
return cell
}
// MARK: - Table view delegate
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
tableView.deselectRowAtIndexPath(indexPath, animated: true)
let key = sortedKeys[indexPath.row]
if (selectedTypes!).contains(key) {
selectedTypes = selectedTypes.filter({$0 != key})
} else {
selectedTypes.append(key)
}
tableView.reloadData()
}
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
//toggle checkmark on and off
if tableView.cellForRow(at: indexPath)?.accessoryType == .checkmark {
tableView.cellForRow(at: indexPath)?.accessoryType = .none
}
else {
tableView.cellForRow(at: indexPath)?.accessoryType = .checkmark
}
//add animation so cell does not stay selected
tableView.deselectRow(at: indexPath, animated: true)
}
Not sure what you are doing in your code. If you want to uncheck then change below line to
cell.accessoryType = (selectedTypes!).contains(key) ? .Checkmark : .None
to
cell.accessoryType = (selectedTypes!).contains(key) ? . None : . Checkmark
Updated:- second part of the answer to get only checkmark cells,
change as below
#IBAction func donePressed(sender: AnyObject) {
let rowCount = tableView.numberOfRowsInSection(0)
selectedTypes.removeAll()
for var index = 0; index < rowCount; ++index {
let cell = tableView.cellForRowAtIndexPath(NSIndexPath(forRow: index, inSection: 0)) as! YourCell
if cell.accessoryType = .Checkmark{
let key = sortedKeys[index]
selectedTypes.append(key)
}
delegate?.typesController(self, didSelectTypes: selectedTypes)
}
}

Swift/iOS 8: search bar raising fatal error: unexpectedly found nil while unwrapping an Optional value

Following this tutorial, I have just added a "Search Bar and Search Display Controller" to my Table View Controller.
As you can see from the following screenshot, the table and the search bar are correctly loaded:
by using "Cell" as cell reuse identifier.
Anyway, there are two problems:
1) When the search bar is tapped it simply disappears under the navigation bar even if it still accepts text to search
2) as soon as I start typing something in the search bar (even if it is "hidden") then an exception mentioned in title is raised.
Here is my code where the line with /***/ is where the exception raises:
import UIKit
class AllTasksViewController: UITableViewController, UISearchBarDelegate, UISearchDisplayDelegate {
var allTasks = [Task]()
var taskService = TaskService()
var organizedTasks = TaskMenuItems()
var filteredTasks = [Task]()
override func viewWillAppear(animated: Bool) {
self.tabBarController?.navigationItem.setHidesBackButton(true, animated: true)
self.tabBarController?.navigationItem.rightBarButtonItem = self.editButtonItem()
if (LoggedUser.isLogged) {
self.navigationItem.setHidesBackButton(false, animated: true)
self.taskService.requestAllTasks {
(response) in
self.allTasks = self.taskService.loadTasks(response) as! [Task]
self.organizedTasks.organize(self.allTasks)
/*println(self.organizedTasks.items["Aperti"]?.count)
println(self.organizedTasks.items["Chiusi"]?.count)
println(self.organizedTasks.items["Scaduti"]?.count)
println(self.organizedTasks.items["Sospesi"]?.count)*/
dispatch_async(dispatch_get_main_queue()) {
self.tableView.reloadData()
}
}
}
}
override func viewDidLoad() {
super.viewDidLoad()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
/* Number of sections */
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return self.organizedTasks.sections.count
}
/* Number of rows for each section */
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if tableView == self.searchDisplayController!.searchResultsTableView {
return self.filteredTasks.count
}
switch section {
case 0:
return self.organizedTasks.items["Aperti"]!.count
case 1:
return self.organizedTasks.items["Chiusi"]!.count
case 2:
return self.organizedTasks.items["Scaduti"]!.count
case 3:
return self.organizedTasks.items["Sospesi"]!.count
default:
return -1
}
}
override func tableView(tableView: UITableView,
cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
l?
var selectedStatus:String
let cell = tableView.dequeueReusableCellWithIdentifier("Cell") as! UITableViewCell /***/
var task:Task
if tableView == self.searchDisplayController!.searchResultsTableView {
task = filteredTasks[indexPath.row]
cell.textLabel?.text = task.titolo
cell.detailTextLabel?.textColor = Settings.decideColor(task.priorita)
cell.detailTextLabel?.text = task.priorita
return cell
}
switch indexPath.section {
case 0:
/*let cell = tableView.dequeueReusableCellWithIdentifier("OpenTasks",
forIndexPath: indexPath) as! UITableViewCell*/
selectedStatus = "Aperti"
break
case 1:
/*let cell = tableView.dequeueReusableCellWithIdentifier("ClosedTasks",
forIndexPath: indexPath) as! UITableViewCell*/
selectedStatus = "Chiusi"
break
case 2:
/*let cell = tableView.dequeueReusableCellWithIdentifier("ExpiredTasks",
forIndexPath: indexPath) as! UITableViewCell*/
selectedStatus = "Scaduti"
break
case 3:
/*let cell = tableView.dequeueReusableCellWithIdentifier("SuspendedTasks",
forIndexPath: indexPath) as! UITableViewCell*/
selectedStatus = "Sospesi"
break
default:
/*let cell = tableView.dequeueReusableCellWithIdentifier("",
forIndexPath: indexPath) as! UITableViewCell*/
selectedStatus = ""
break
}
task = self.organizedTasks.items[selectedStatus]![indexPath.row]
cell.textLabel?.text = task.titolo
cell.detailTextLabel?.textColor = Settings.decideColor(task.priorita)
cell.detailTextLabel?.text = task.priorita
return cell
}
override func tableView(tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
switch (section) {
case 0:
let count = self.organizedTasks.items["Aperti"]!.count
return "Aperti (\(count))"
case 1:
let count = self.organizedTasks.items["Chiusi"]!.count
return "Chiusi (\(count))"
case 2:
let count = self.organizedTasks.items["Scaduti"]!.count
return "Scaduti (\(count))"
case 3:
let count = self.organizedTasks.items["Sospesi"]!.count
return "Sospesi (\(count))"
default:
return ""
}
}
func filterContentForSearchText(searchText: String, scope:String="All") {
// Filter the array using the filter method
self.filteredTasks = self.allTasks.filter({( task: Task) -> Bool in
let categoryMatch = (scope == "All") || (task.priorita == scope)
let stringMatch = task.titolo.rangeOfString(searchText)
return categoryMatch && (stringMatch != nil)
})
}
func searchDisplayController(controller: UISearchDisplayController, shouldReloadTableForSearchString searchString: String!) -> Bool {
self.filterContentForSearchText(searchString)
return true
}
func searchDisplayController(controller: UISearchDisplayController, shouldReloadTableForSearchScope searchOption: Int) -> Bool {
self.filterContentForSearchText(self.searchDisplayController!.searchBar.text)
return true
}
// In a storyboard-based application, you will often want to do a little preparation before navigation
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
// Get the new view controller using [segue destinationViewController].
// Pass the selected object to the new view controller.
}
}
I don't know why these two things happen. It seems that it can't create another cell with "Cell" identifier but this is strange because when the table is loaded (without using the search bar) all is ok so the identifier Cell is registered.
Please, can you help?
Try the following code where you have configured your search display controller or in viewDidLoad:
self.searchDisplayController.searchResultsTableView.registerClass(UITableViewCell.self, forCellReuseIdentifier: "Cell")
Also, use tableView.
dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath)
It's worth mentioning that, UISearchDisplayController is deprecated in iOS 8, use UISearchController instead.

SideMenuBar dont load

I have a sidebar menu made with a tableview. When the user click on one cell from the sidebar, it shows a tableview with categories (check image below). The problem i'm facing is that I click on a cell from the sidebar and it loads the right viewcontroller, but if I click again it does not load, it simply knows that the column is the same one, it does nothing.
I think its a problem in the sidebar that do not load the content because it knows its the same indexPath. No? Thank you
Screen:
My Sidebar code:
import UIKit
import Parse
var opcoesSideMenu: [String] = ["Inicio","Perfil","Restaurantes","Categorias","Meu Restaurante","Sair"]
class MyMenuTableViewController: UITableViewController {
var selectedMenuItem : Int = 0
override func viewDidLoad() {
super.viewDidLoad()
// Customize apperance of table view
tableView.contentInset = UIEdgeInsetsMake(64.0, 0, 0, 0) //
tableView.separatorStyle = .None
tableView.backgroundColor = UIColor.clearColor()
tableView.scrollsToTop = false
// Preserve selection between presentations
self.clearsSelectionOnViewWillAppear = false
tableView.selectRowAtIndexPath(NSIndexPath(forRow: selectedMenuItem, inSection: 0), animated: false, scrollPosition: .Middle)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
// MARK: - Table view data source
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
// Return the number of sections.
return 1
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// Return the number of rows in the section.
return opcoesSideMenu.count
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var cell = tableView.dequeueReusableCellWithIdentifier("cellmenu") as? UITableViewCell
if (cell == nil) {
cell = UITableViewCell(style: UITableViewCellStyle.Default, reuseIdentifier: "cellmenu")
cell!.backgroundColor = UIColor.clearColor()
cell!.textLabel?.textColor = UIColor.whiteColor()
let selectedBackgroundView = UIView(frame: CGRectMake(0, 0, cell!.frame.size.width, cell!.frame.size.height))
selectedBackgroundView.backgroundColor = UIColor.grayColor().colorWithAlphaComponent(0.2)
cell!.selectedBackgroundView = selectedBackgroundView
}
// cell!.textLabel?.text = "ViewController #\(indexPath.row+1)"
cell!.textLabel?.text = opcoesSideMenu[indexPath.row] as String
if cell!.textLabel?.text == "Meu Restaurante" {
if localizacaoActualizada.temRestaurante == false {
// cell!.textLabel?.textColor = UIColorFromRGB(0x303E73)
}
}
//Vai procurar uma imagem com o mesmo nome que o que esta no array OpcoesSideMenu e colocado ao lado do texto
var imageName = UIImage(named: opcoesSideMenu[indexPath.row])
cell!.imageView?.image = imageName
return cell!
}
override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
return 50.0
}
override func tableView(tableView: UITableView, willSelectRowAtIndexPath indexPath: NSIndexPath) -> NSIndexPath? {
if localizacaoActualizada.temRestaurante == false {
if indexPath.row == 4 {return nil}
}
return indexPath
}
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
println("Selected row: \(indexPath.row)")
if (indexPath.row == selectedMenuItem) {
return
}
selectedMenuItem = indexPath.row
//Present new view controller
let mainStoryboard: UIStoryboard = UIStoryboard(name: "Main",bundle: nil)
var destViewController : UIViewController
switch (indexPath.row) {
case 0:
destViewController = mainStoryboard.instantiateViewControllerWithIdentifier("listarRestaurantes") as! UIViewController
break
case 1:
destViewController = mainStoryboard.instantiateViewControllerWithIdentifier("perfilUtilizador")as! UIViewController
break
case 2:
destViewController = mainStoryboard.instantiateViewControllerWithIdentifier("categorias")as! UIViewController
break
case 3:
destViewController = mainStoryboard.instantiateViewControllerWithIdentifier("perfilRestaurante")as! UIViewController
break
case 4:
PFUser.logOut()
destViewController = mainStoryboard.instantiateViewControllerWithIdentifier("ViewController1") as! UIViewController
break
default:
destViewController = mainStoryboard.instantiateViewControllerWithIdentifier("Inicio") as! UIViewController
break
}
sideMenuController()?.setContentViewController(destViewController)
}
}

Resources