Custom UITableViewCell causing UISearchBar to crash - ios

I have a tableView with a UISearchBar set up. Every time the user starts typing in the search bar the app crashes. I discovered that the problem is that I'm using a custom tableViewCell (when I tried running the app with the default tableViewCell it didn't crash and worked fine.). Any ideas on how to fix this? Thanks.
Here's my code:
import UIKit
import CoreData
class KeepTableViewController: UITableViewController, UISearchBarDelegate{
#IBOutlet weak var searchBar: UISearchBar!
var filteredQuotes = [AnyObject]()
var keptQuotes = [NSManagedObject]()
override func viewDidLoad() {
super.viewDidLoad()
searchBar.delegate = self
searchBar.showsScopeBar = true
tableView.rowHeight = UITableViewAutomaticDimension
getCoreData()
searchDisplayController?.searchResultsTableView.registerClass(QuoteyTableViewCell.self, forCellReuseIdentifier: "Cell")
}
func getCoreData(){
var appDel : AppDelegate = UIApplication.sharedApplication().delegate as AppDelegate
var context : NSManagedObjectContext = appDel.managedObjectContext!
var req : NSFetchRequest = NSFetchRequest(entityName: "KeptQuotes")
var error : NSError?
let fetchedResults = context.executeFetchRequest(req, error: &error) as [NSManagedObject]?
if let results = fetchedResults {
keptQuotes = results
}else{
println("Could not fetch \(error), \(error!.userInfo)")
}
tableView.reloadData()
}
#IBAction func cancelPressed(sender: AnyObject) {
dismissViewControllerAnimated(true, completion: nil) //dismisses the freakin view
}
override func preferredStatusBarStyle() -> UIStatusBarStyle {
return UIStatusBarStyle.LightContent
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
// MARK: - Table view data source
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
// #warning Potentially incomplete method implementation.
// Return the number of sections.
return 1
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// #warning Incomplete method implementation.
// Return the number of rows in the section.
if tableView == self.searchDisplayController?.searchResultsTableView {
return filteredQuotes.count
}else{
return keptQuotes.count
}
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell : QuoteyTableViewCell = tableView.dequeueReusableCellWithIdentifier("Cell") as QuoteyTableViewCell
var entry : NSManagedObject
if tableView == self.searchDisplayController!.searchResultsTableView{
entry = filteredQuotes[indexPath.row] as NSManagedObject
}else{
entry = keptQuotes[indexPath.row] as NSManagedObject!
}
cell.authorLabel.text = entry.valueForKey("author") as String!
cell.quoteTextLabel.text = entry.valueForKey("quote") as String!
cell.quoteTextLabel.sizeToFit()
cell.selectionStyle = UITableViewCellSelectionStyle.None
return cell
}
func filterContentForSearchText(searchText: String) {
var qs : NSArray = keptQuotes
let predicate = NSPredicate(format: "quote contains[c] %# OR author contains[c] %#", searchText, searchText)
filteredQuotes = qs.filteredArrayUsingPredicate(predicate!)
println(filteredQuotes)
}
func searchDisplayController(controller: UISearchDisplayController!, shouldReloadTableForSearchString searchString: String!) -> Bool {
self.filterContentForSearchText(searchString)
return true
}
func searchDisplayController(controller: UISearchDisplayController!, shouldReloadTableForSearchScope searchOption: Int) -> Bool {
self.filterContentForSearchText(searchDisplayController!.searchBar.text)
return true
}
}
Custom TableViewCell:
import UIKit
class QuoteyTableViewCell: UITableViewCell {
#IBOutlet weak var authorLabel: UILabel!
#IBOutlet weak var quoteTextLabel: UILabel!
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
quoteTextLabel.textColor = UIColor(rgba: "#293B50")
authorLabel.textColor = UIColor(rgba: "#A4ACB5")
}
override func setSelected(selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
}

I came across the same problem as yours too not too long ago. What I did to make mine work was instead of laying out my custom cell directly in the prototype cell, I created a separate .xib file for it, set the prototype cells in my tableViewController to 0 and did
let regularCell = UINib(nibName: "Cell", bundle: nil)
self.searchDisplayController!.searchResultsTableView.registerNib(regularCell, forCellReuseIdentifier: "Cell")

Related

UISearchController crash when selected

I tried to implement a UISearchController into my ViewController. However, when I try to open up the Controller from a button it crashes the application and there is no error given to me from Xcode. I am using Backendless to store users and to retrieve them. I want to search through them.
Here is my code. I don't know what I am doing wrong :/ I would really appreciate the help.
import UIKit
protocol ChooseUserDelegate {
func chreatChatroom(withUser: BackendlessUser)
}
class ChooseUserViewController: UIViewController, UITableViewDelegate, UITableViewDataSource, UISearchResultsUpdating {
#IBOutlet weak var tableView: UITableView!
var delegate: ChooseUserDelegate!
var users: [BackendlessUser] = []
var filteredUsers = [BackendlessUser]()
var resultSearchController: UISearchController!
override func viewDidLoad() {
super.viewDidLoad()
loadUsers()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
//MARK: UITableviewDataSorce
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
func updateSearchResultsForSearchController(searchController: UISearchController) {
self.filteredUsers.removeAll(keepCapacity: false)
let searchPredicate = NSPredicate(format: "SELF CONTAINS[c] %#", searchController.searchBar.text!); let array = (self.users as NSArray).filteredArrayUsingPredicate(searchPredicate)
self.filteredUsers = array as! [BackendlessUser]
self.tableView.reloadData()
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if resultSearchController.active
{
return self.filteredUsers.count
} else {
return users.count
}
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as UITableViewCell?
if self.resultSearchController.active
{
let userFiltered = filteredUsers[indexPath.row]
cell!.textLabel?.text = userFiltered.name
} else {
let user = users[indexPath.row]
cell!.textLabel?.text = user.name
}
return cell!
}
//MARK: UITableviewDelegate
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
let user = users[indexPath.row]
delegate.chreatChatroom(user)
tableView.deselectRowAtIndexPath(indexPath, animated: true)
self.dismissViewControllerAnimated(true, completion: nil)
}
//MARK: IBactions
#IBAction func cancelButtonPressed(sender: AnyObject) {
self.dismissViewControllerAnimated(true, completion: nil)
}
//MARK: Load Backendless Users
func loadUsers() {
let whereClause = "objectId != '\(backendless.userService.currentUser.objectId)'"
let dataQuery = BackendlessDataQuery()
dataQuery.whereClause = whereClause
let dataStore = backendless.persistenceService.of(BackendlessUser.ofClass())
dataStore.find(dataQuery, response: { (users : BackendlessCollection!) -> Void in
self.users = users.data as! [BackendlessUser]
self.resultSearchController = UISearchController(searchResultsController: nil)
self.resultSearchController.searchResultsUpdater = self
self.resultSearchController.dimsBackgroundDuringPresentation = false
self.resultSearchController.searchBar.sizeToFit()
self.tableView.tableHeaderView = self.resultSearchController.searchBar
self.tableView.reloadData()
}) { (fault : Fault!) -> Void in
print("Error, couldnt retrieve users: \(fault)")
}
}
}
Your resultSearchController is nil before it is used. It's set in a closure that almost certainly sets it after it's needed when setting up the view. To fix it, just move this initialization code to something earlier like viewDidLoad():
self.resultSearchController = UISearchController(searchResultsController: nil)
self.resultSearchController.searchResultsUpdater = self
self.resultSearchController.dimsBackgroundDuringPresentation = false
self.resultSearchController.searchBar.sizeToFit()
self.tableView.tableHeaderView = self.resultSearchController.searchBar

Return number field from Parse into Tableview custom cell

I have a tableview controller with a custom Prototype Cell. The cell contains 2 labels. I am trying to return 2 values from a Parse class. One field is called Notes and is a String value. The other field is called CreditAmount and is a number value. I am having difficulty returning the number value (Credit Amount) in my tableview.
Here is code for tableview controller:
import UIKit
import Parse
import Foundation
class TableViewController: UITableViewController {
var note = [String]()
var credit = [NSInteger]()
var refresher: UIRefreshControl!
override func viewDidLoad() {
super.viewDidLoad()
self.tableView.reloadData()
updateNotes()
self.refresher = UIRefreshControl()
self.refresher.attributedTitle = NSAttributedString(string: "Pull to refresh")
self.refresher.addTarget(self, action: "refresh:", forControlEvents: UIControlEvents.ValueChanged)
self.tableView.addSubview(refresher)
}
func updateNotes() {
let query = PFQuery(className: "Paydown")
query.findObjectsInBackgroundWithBlock({ (objects:[AnyObject]?, error: NSError?) -> Void in
self.note.removeAll(keepCapacity: true)
self.credit.removeAll(keepCapacity: true)
if let objects = objects as? [PFObject] {
for object in objects {
// var noted = object as PFObject
self.note.append(object["Notes"] as! String)
self.credit.append(object["CreditAmount"] as! NSInteger)
}
self.tableView.reloadData()
} else {
//println(error)
}
self.refresher.endRefreshing()
})
}
func refresh() {
updateNotes()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
// MARK: - Table view data source
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
// #warning Potentially incomplete method implementation.
// Return the number of sections.
return 1
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return note.count
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let myCell = tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath) as! cell
myCell.notesLabel.text = note[indexPath.row]
myCell.amountLabel.text = credit[indexPath.row]
return myCell
}
}
Here is the code for my customer cell:
import UIKit
import Parse
class cell: UITableViewCell {
#IBOutlet weak var notesLabel: UILabel!
#IBOutlet weak var amountLabel: UILabel!
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
}
}
The myCell.amountLabel.text = credit[indexPath.row] causes an error: cannot assign a value of type NSInteger (aka int) to a value of type String?. How do I get the number field to work?
Update
myCell.amountLabel.text = credit[indexPath.row]
To be
myCell.amountLabel.text = "\(credit[indexPath.row])"

Cannot subscript a value of type dictionary with an index of type Int

Working on an IOS app(swift 1.2, Xcode 6.3), I'm implementing the UISearchController in a ViewController and I'm getting an error in the data source method (cellForRowAtIndexPath) when I try return a cell for a table view, becouse I don't know to obtain an indexpath.row from a dictionary. The error is Cannot subscript a value of type [String : AnyObject] with an index of type Int and the code of the view controller is:
import Foundation
import UIKit
class UsersViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
#IBOutlet var tableview:UITableView!
let apiClient = ApiClient()
var users: [User]!
var searchArray:[AnyObject] = [AnyObject](){
didSet {self.tableview.reloadData()}
}
var usersSearchController = UISearchController()
override func viewDidLoad() {
super.viewDidLoad()
self.usersSearchController = ({
// Two setups provided below:
// Setup One: This setup present the results in the current view.
let controller = UISearchController(searchResultsController: nil)
controller.searchResultsUpdater = self
controller.hidesNavigationBarDuringPresentation = false
controller.dimsBackgroundDuringPresentation = false
controller.searchBar.searchBarStyle = .Minimal
controller.searchBar.sizeToFit()
self.tableview.tableHeaderView = controller.searchBar
return controller
})()
}
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
println("UsersController viewWillAppear")
apiClient.usersService.getList() { users, error in
if users != nil {
self.users = users
self.tableview?.reloadData()
} else {
println("error: \(error)")
}
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if ( self.usersSearchController.active){
return self.searchArray.count ?? 0
} else {
return self.users?.count ?? 0
}
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var cell = tableView.dequeueReusableCellWithIdentifier("userObjectCell") as! UserTableViewCell
if (self.usersSearchController.active){
cell.userObject = self.searchArray[indexPath.row] as? User//HERE IS THE ERROR
return cell
} else {
cell.userObject = self.users?[indexPath.row]
return cell
}
}
}
extension UsersViewController: UITableViewDelegate
{
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath)
{
tableView.deselectRowAtIndexPath(indexPath, animated: true)
}
}
extension UsersViewController: UISearchResultsUpdating
{
func updateSearchResultsForSearchController(searchController: UISearchController)
{
// self.searchArray.removeAll(keepCapacity: false)
//
// let searchPredicate = NSPredicate(format: "SELF CONTAINS[c] %#", searchController.searchBar.text)
// let array = (self.users as NSArray).filteredArrayUsingPredicate(searchPredicate)
// self.searchArray = array as! [String: AnyObject]
}
}
Dictionaries don't have indexes, they have keys. You may want to consider a method of parsing your dictionary data and putting it into an ordered list, like an Array, so your data will appear in the same place. (Dictionaries are not ordered).

PopOver TableView, error at cell in Swift IOS 8

i am using ViewController in my application. in ViewController i try to popOver tableview using textfield. but having error
this my code popUp :
Func textFieldShouldBeginEditing(textField: UITextField) -> Bool{
if (textField == paymentTextField){
var paymentVC = MasterPaymentTableViewController()
paymentVC.modalPresentationStyle = .Popover
paymentVC.preferredContentSize = CGSizeMake(300, 500)
let popOverPresentationVC = paymentVC.popoverPresentationController
popOverPresentationVC?.delegate = self
popOverPresentationVC?.permittedArrowDirections = .Down
popOverPresentationVC?.sourceView = textField as UIView
self.navigationController?.presentViewController(paymentVC, animated: true, completion: nil)
return false
}
}
this error at code :
import UIKit
import CoreData
class MasterPaymentTableViewController: UITableViewController {
var myList : Array<AnyObject> = []
var appDel : AppDelegate!
var context : NSManagedObjectContext!
override func viewDidLoad() {
super.viewDidLoad()
}
override func viewDidAppear(animated: Bool) {
appDel = UIApplication.sharedApplication().delegate as! AppDelegate
context = appDel.managedObjectContext
let freq = NSFetchRequest(entityName: "PayMethod")
myList = context.executeFetchRequest(freq, error: nil)!
tableView.reloadData()
}
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 1
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return myList.count
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath?) -> UITableViewCell {
let cellID : String = "Cell"
// ERROR AT HERE : unexpectedly found nil while unwrapping an Optional value
var cell = tableView.dequeueReusableCellWithIdentifier(cellID) as! UITableViewCell
// -------------
if let ip = indexPath {
var myObject : NSManagedObject = myList[ip.row] as! NSManagedObject
let title = myObject.valueForKeyPath("paymentName") as! String
cell.textLabel!.text = title
}
return cell
}
But, if i open tableView directly not from popOver, its working normal
any solution?
thx
Try this:
override func viewDidLoad() {
super.viewDidLoad()
tableView.registerClass(UITableViewCell.self, forCellReuseIdentifier: "Cell")
}
and use the dequeueReusableCellWithIdentifier:forIndexPath: method instead of using dequeueReusableCellWithIdentifier:
let cell = tableView.dequeueReusableCellWithIdentifier(cellID, forIndexPath:indexPath)

Swift Use of Unresolved Identifier 'IndexPath' TableView Cell Button

I am attempting to get the text of my UILabel and set it to my Parse object, but I am running into an issue setting the object to the index path of the cell. I am getting an Use of unresolved identifier 'indexPath' error at that line.
follow["following"] = self.userArray.objectAtIndex(IndexPath.row)
Here is my tableview controller:
import UIKit
class SearchUsersRegistrationTableViewController: UITableViewController {
var userArray : NSMutableArray = []
override func viewDidLoad() {
super.viewDidLoad()
var user = PFUser.currentUser()
loadParseData()
}
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 1
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return userArray.count
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell: SearchUsersRegistrationTableViewCell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as! SearchUsersRegistrationTableViewCell
let row = indexPath.row
var individualUser = userArray[row] as! PFUser
var username = individualUser.username as String
var profileImage = individualUser["profileImage"] as? PFFile
if profileImage != nil {
profileImage!.getDataInBackgroundWithBlock({
(result, error) in
cell.userImage.image = UIImage(data: result)
})
} else {
cell.userImage.image = UIImage(named: "profileImagePlaceHolder")
}
cell.usernameLabel.text = username
cell.addUserButton.tag = row
cell.addUserButton.addTarget(self, action: "addUser:", forControlEvents: .TouchUpInside)
return cell
}
func loadParseData() {
var query : PFQuery = PFUser.query()
query.findObjectsInBackgroundWithBlock {
(objects:[AnyObject]!, error:NSError!) -> Void in
if error == nil {
if let objects = objects {
println("\(objects.count) users are listed")
for object in objects {
self.userArray.addObject(object)
}
self.tableView.reloadData()
}
} else {
println("There is an error")
}
}
}
#IBAction func addUser(sender: UIButton) {
println("Button Triggered")
let addUserButton : UIButton = sender
let user : PFObject = self.userArray.objectAtIndex(addUserButton.tag) as! PFObject
var follow = PFObject(className: "Follow")
follow["following"] = self.userArray.objectAtIndex(IndexPath.row)
follow["follower"] = PFUser.currentUser().username
follow.saveInBackground()
}
}
Here is my tableview cell:
import UIKit
class SearchUsersRegistrationTableViewCell: UITableViewCell {
#IBOutlet weak var userImage: UIImageView!
#IBOutlet weak var usernameLabel: UILabel!
#IBOutlet weak var addUserButton: UIButton!
override func awakeFromNib() {
super.awakeFromNib()
userImage.layer.borderWidth = 1
userImage.layer.masksToBounds = false
userImage.layer.borderColor = UIColor.whiteColor().CGColor
userImage.layer.cornerRadius = userImage.frame.width/2
userImage.clipsToBounds = true
}
override func setSelected(selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
}
Try this
follow["following"] = self.userArray.objectAtIndex(sender.tag)
You are setting the row as tag for your button. Just use it.
you should not work with tags in that case.
to get the indexpath in your addUser function add the following:
let indexPath = tableView.indexPathForRowAtPoint(addUserButton.convertPoint(CGPointZero, toView: tableView))
then you can use that line:
follow["following"] = self.userArray.objectAtIndex(indexPath.row)
indexPath, not IndexPath

Resources