Swift - Array index out of range warning - ios

My code has an issue when I run the iOS simulator. It breaks and brings me to the line of code:let targetUser = users[indexPath.row] and says 'EXC_BAD_INSTRUCTION (CODE=EXC_1386_INVOP,snbcode = 0x0)' would anyone be able to help me figure out why?
class OverviewTableViewController: UITableViewController {
#IBOutlet weak var LogoutButton: UIBarButtonItem!
#IBOutlet weak var ChoosePartnerButton: UIBarButtonItem!
var rooms = [PFObject]()
var users = [PFUser]()
override func viewDidLoad() {
super.viewDidLoad()
self.navigationItem.setLeftBarButtonItem(LogoutButton, animated: false)
self.navigationItem.setRightBarButtonItem(ChoosePartnerButton, animated: false)
}
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
if PFUser.currentUser() != nil {
loadData()
}
}
func loadData() {
rooms = [PFObject]()
users = [PFUser]()
self.tableView.reloadData()
let pred = NSPredicate(format: "user1 = %# OR user2 = %#", PFUser.currentUser()!, PFUser.currentUser()!)
let roomQuery = PFQuery(className: "Room", predicate: pred)
roomQuery.includeKey("user1")
roomQuery.includeKey("user2")
roomQuery.findObjectsInBackgroundWithBlock { (results:[AnyObject]?, error:NSError?) -> Void in
if error == nil {
self.rooms = results as! [PFObject]
for room in self.rooms {
let user1 = room.objectForKey("user1") as! PFUser
let user2 = room["user2"] as! PFUser
if user1.objectId != PFUser.currentUser()?.objectId {
self.users.append(user1)
}
if user2.objectId != PFUser.currentUser()?.objectId {
self.users.append(user2)
}
}
self.tableView.reloadData()
}
}
}
// 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 rooms.count
}
override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
return 80
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as! OverviewTableViewCell
let targetUser = users[indexPath.row]
cell.nameLabel.text = targetUser.username
return cell
}

Sounds like #MartinR had nailed it. You're reading rooms.count in numberOfRowsInSection, but then looking up data from the users array in cellForRowAtIndexPath.
You could figure this out in the debugger by examining indexPath.row when you crash, and examining the size of rooms.count as well.

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

am trying to implement search bar in my app so that i can search the objects which are retrieved from parse.com

import UIKit
class MasterTableViewController: UITableViewController, PFLogInViewControllerDelegate, PFSignUpViewControllerDelegate, UISearchBarDelegate, UISearchDisplayDelegate {
#IBOutlet var searchBar: UISearchBar!
// creating array for holding ojects
var noteObjects: NSMutableArray! = NSMutableArray()
var v = 0
var searchActive : Bool = false
var data:[PFObject]!
var filtered:[PFObject]!
override func viewDidLoad() {
super.viewDidLoad()
searchBar.delegate = self
}
override func viewDidAppear(animated: Bool) {
super.viewDidAppear(animated)
if v == 0 {
self.fetchAllObjectsFromLocalDataStore()
//self.fetchAllObjects()
}
}
// fetching data from local datastrore and from parse
func fetchAllObjectsFromLocalDataStore(){
let query: PFQuery = PFQuery(className: "className")
query.orderByDescending("createdAt")
query.fromLocalDatastore()
query.findObjectsInBackgroundWithBlock { (var objects, error) -> Void in
self.search()
if (error == nil) {
let temp: NSArray = objects as! NSArray
self.noteObjects = temp.mutableCopy() as! NSMutableArray
self.search()
self.tableView.reloadData()
}else {
print(error!.userInfo)
}
}
}
func fetchAllObjects(){
let query: PFQuery = PFQuery(className: "className")
query.orderByDescending("createdAt")
search()
query.findObjectsInBackgroundWithBlock { (objects, error) -> Void in
if (error == nil) {
PFObject.pinAllInBackground(objects, block: nil )
self.fetchAllObjectsFromLocalDataStore()
// self.tableView.reloadData()
} else {
print(error?.userInfo)
}
}
}
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 Incomplete implementation, return the number of sections
return 1
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// #warning Incomplete implementation, return the number of rows
return self.noteObjects.count
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = self.tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath) as! MasterTableViewCell
let object : PFObject = self.noteObjects.objectAtIndex(indexPath.row) as! PFObject
cell.MasterTitleLabel?.text = object["Title"] as? String
cell.MasterTextLabel.text = object["Fstory"] as? String
cell.MasterTimeLabel.text = object["Time"] as? String
cell.MasterLocationLabel.text = object["Location"] as? String
return cell
}
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
self.performSegueWithIdentifier("openStory", sender: self)
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
let upcoming: AddNoteTableViewController = segue.destinationViewController as! AddNoteTableViewController
if (segue.identifier == "openStory"){
let indexPath = self.tableView.indexPathForSelectedRow!
let object: PFObject = self.noteObjects.objectAtIndex(indexPath.row) as! PFObject
upcoming.object = object
self.tableView.deselectRowAtIndexPath(indexPath, animated: true)
}
}
#IBAction func btnReload(sender: AnyObject) {
fetchAllObjects()
}
override func tableView(tableView: UITableView, canEditRowAtIndexPath indexPath: NSIndexPath) -> Bool {
return true
}
override func tableView(tableView: UITableView, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath) {
if (editingStyle == UITableViewCellEditingStyle.Delete ){
let object : PFObject = self.noteObjects.objectAtIndex(indexPath.row) as! PFObject
// the below for deleting the selected cell's object from server's database
// object.deleteInBackground()
//the below for deleting the selected cell's object from localstorage
object.unpinInBackground()
self.noteObjects.removeObjectAtIndex(indexPath.row)
tableView.deleteRowsAtIndexPaths([indexPath], withRowAnimation: UITableViewRowAnimation.Automatic)
}
}
func search(searchText: String? = nil){
let query = PFQuery(className: "className")
if(searchText != nil){
query.whereKey("Title", containsString: searchText)
}
query.findObjectsInBackgroundWithBlock { (results, error) -> Void in
self.data = results! as [PFObject]
self.tableView.reloadData()
}
}
func searchBarTextDidBeginEditing(searchBar: UISearchBar) {
searchActive = true;
}
func searchBarTextDidEndEditing(searchBar: UISearchBar) {
searchActive = false;
}
func searchBarCancelButtonClicked(searchBar: UISearchBar) {
searchActive = false;
}
func searchBarSearchButtonClicked(searchBar: UISearchBar) {
searchActive = false;
}
}
the above code is for retrieving parse's objects and for implementing the search bar so that i can search my objects via search function but i don't what am missing or how to it properly if anybody knows than please help me
you can try something like this using UIsearchBar
class TableViewController: UITableViewController, UISearchBarDelegate {
#IBOutlet var searchBar: UISearchBar!
var userList:NSMutableArray = NSMutableArray()
var noteObjects: NSMutableArray = NSMutableArray()
override func viewDidLoad() {
super.viewDidLoad()
searchBar.delegate = self
self.fetchAllObjectsFromLocalDataStore()
}
func loadUsers(name:String){
var findUsers:PFQuery = PFUser.query()!
if !name.isEmpty{
findUsers.whereKey("username", containsString: name)
findUsers.whereKey("username", containsString: name .lowercaseString)
let user = PFUser.currentUser()
if let user = PFUser.currentUser() {
findUsers.whereKey("institute", equalTo: user["institute"])
}
}
findUsers.fromLocalDatastore()
findUsers.findObjectsInBackgroundWithBlock { ( objects, error) -> Void in
if (error == nil) {
self.userList = NSMutableArray(array: objects!)
self.tableView.reloadData()
}else {
print(error!.userInfo)
}
}}
func searchBar(searchBar: UISearchBar, textDidChange searchText: String) {
loadUsers(searchText)
self.searchBar.setShowsCancelButton(true, animated: true)
}
func searchBarCancelButtonClicked(searchBar: UISearchBar) {
loadUsers("")
self.searchBar.setShowsCancelButton(false, animated: true)
self.searchBar.endEditing(true)
}
// MARK: - Table view data source
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
// #warning Incomplete implementation, return the number of sections
return 1
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// #warning Incomplete implementation, return the number of rows
if searchBar.text == "" {
return noteObjects.count
} else {
return userList.count }
//self.noteObjects.count
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = self.tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath) as! UsersTableViewCell
if searchBar.text == "" {
let object : PFObject = self.noteObjects.objectAtIndex(indexPath.row) as! PFObject
let photo: PFFile = object["photo"] as! PFFile
photo.getDataInBackgroundWithBlock{
(imageData:NSData?, error:NSError?)-> Void in
if (error == nil){
let image:UIImage = UIImage(data: imageData!)!
cell.imgViewUser.image = image
}
else if error != nil{
print("error")
}
}
cell.lblUserInterest.text = object["interest"] as? String
//cell.imgViewUser.image = object["photo"] as? PFFile
cell.lblUsername.text = object["username"] as? String
return cell
} else {
let object : PFObject = self.userList.objectAtIndex(indexPath.row) as! PFObject
let photo: PFFile = object["photo"] as! PFFile
photo.getDataInBackgroundWithBlock{
(imageData:NSData?, error:NSError?)-> Void in
if (error == nil){
let image:UIImage = UIImage(data: imageData!)!
cell.imgViewUser.image = image
}
else if error != nil{
print("error")
}}
cell.lblUserInterest.text = object["interest"] as? String
//cell.imgViewUser.image = object["photo"] as? PFFile
cell.lblUsername.text = object["username"] as? String
return cell
}
}
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
var object :AnyObject?
}
override func tableView(tableView: UITableView, canEditRowAtIndexPath indexPath: NSIndexPath) -> Bool {
return true
}
override func tableView(tableView: UITableView, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath) {
if (editingStyle == UITableViewCellEditingStyle.Delete ){
}

SWIFT: Difficultly displaying data in tableView

I am attempting to display data from Parse onto the following tableView controller. For some reason, the data is not displaying on the tableView (i.e. the rows are blank). I do not think that the data queried from Parse is being appended to the arrays. I am wondering what I'm doing wrong here.
Here's the current output:
I am using a custom prototype cell with identifier "CellTrack" class "TrackTableViewCell" and as shown below:
Here is my code in the TableViewController file:
import UIKit
import Parse
class MusicPlaylistTableViewController: UITableViewController {
var usernames = [String]()
var songs = [String]()
var dates = [String]()
override func viewDidLoad() {
super.viewDidLoad()
}
override func viewWillAppear(animated: Bool) {
var query = PFQuery(className:"PlaylistData")
query.findObjectsInBackgroundWithBlock { (objects: [PFObject]?, error: NSError?) -> Void in
if error == nil {
if let objects = objects! as? [PFObject] {
self.usernames.removeAll()
self.songs.removeAll()
self.dates.removeAll()
for object in objects {
let username = object["username"] as? String
self.usernames.append(username!)
print("added username")
let track = object["song"] as? String
self.songs.append(track!)
let date = object["createdAt"] as? String
self.dates.append(date!)
self.tableView.reloadData()
}
}
} else {
print(error)
}
}
}
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 Incomplete implementation, return the number of sections
return 1
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// #warning Incomplete implementation, return the number of rows
return usernames.count
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("CellTrack", forIndexPath: indexPath) as! TrackTableViewCell
cell.username.text = usernames[indexPath.row]
cell.songTitle.text = songs[indexPath.row]
cell.CreatedOn.text = dates[indexPath.row]
return cell
}
}
And here is my code in the "TrackTableViewCell.swift" class:
import UIKit
class TrackTableViewCell: UITableViewCell {
#IBOutlet weak var songTitle: UILabel!
#IBOutlet weak var username: UILabel!
#IBOutlet weak var CreatedOn: 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
}
}
Execute your tableView.reloadData() in main thread.
dispatch_async(dispatch_get_main_queue(), {
self.tableViewCell.reloadData()
})
Try doing a guard let to see if those values are actually coming back as string or not. My guess would be that the value for created at never came back. Try it out and let me know.
guard let username = object["username"] as? String else {
print ("could not get username")
}
self.usernames.append(username)
print("added username")
guard let track = object["song"] as? String else {
print ("could not get song")
return
}
self.songs.append(track)
guard let date = object["createdAt"] as? String else {
print ("could not get createdAt")
return}
self.dates.append(date!)
func dequeueReusableCellWithIdentifier(_ identifier: String) -> UITableViewCell?
Return Value
A UITableViewCell object with the associated identifier or nil if no such object exists in the reusable-cell queue.
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var cell = tableView.dequeueReusableCellWithIdentifier("CellTrack", forIndexPath: indexPath) as! TrackTableViewCell
if cell == nil {
// create a new cell here
cell = TrackTableViewCell(...)
}
cell.username.text = usernames[indexPath.row]
cell.songTitle.text = songs[indexPath.row]
cell.CreatedOn.text = dates[indexPath.row]
return cell
}

Extra white space above table view swift Xcode

I had an error with Xcode where I needed to fix the size class. After I did that, I went back to one of my table views, and it added white space above the first prototype cells in the tableview. How can I get rid of that space? I added this picture below to better describe what I mean.
https://www.dropbox.com/s/7ebxipb0r2jakav/TableViewProblem.png?dl=0
#IBOutlet var schoolTable: UITableView!
var namesArray = [String]()
var locationsArray = [String]()
var currentUser = PFUser.currentUser()
var theSchoolName: String = "None Selected"
override func viewDidLoad() {
super.viewDidLoad()
}
override func viewDidAppear(animated: Bool) {
namesArray.removeAll(keepCapacity: false)
locationsArray.removeAll(keepCapacity: false)
var query = PFQuery(className: "Schools")
query.findObjectsInBackgroundWithBlock { (objects: [AnyObject]?, error: NSError?) -> Void in
if error == nil {
if let objects = query.findObjects() as? [PFObject] {
for object in objects {
self.namesArray.append(object.valueForKey("schoolName") as! String)
self.locationsArray.append(object.valueForKey("schoolLocation") as! String)
self.schoolTable.reloadData()
}
}
} else {
println("Oops, it didn't work...")
}
}
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.namesArray.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var cell:ChangeSchoolListTableViewCell = tableView.dequeueReusableCellWithIdentifier("Cell") as! ChangeSchoolListTableViewCell
if namesArray.count > 0 {
cell.nameLabel.text = namesArray[indexPath.row]
cell.locationLabel.text = locationsArray[indexPath.row]
}
return cell
}
I've seen this a lot with Xcode storyboards.
The solution is to move the UITableView so its not the first view on the screen.
Space at the top of UITableViews

Swift parse query results not appearing in tableview

I am running into difficulty displaying the data from the query I made in the individual cells of my tableview. I believe that my logic is correct, but I'm not seeing the console.log's that I am calling within my function that contains the Parse queried data. This might be a simple fix, but it isn't coming to me at the moment. The console log I should be seeing to validate that my query is coming through correctly is the println("\(objects.count) users are listed"), it should then be displayed within the usernameLabel.text property.
import UIKit
class SearchUsersRegistrationViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
var userArray : NSMutableArray = []
#IBOutlet var tableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
tableView.delegate = self
tableView.dataSource = self
loadParseData()
}
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")
}
}
}
let textCellIdentifier = "Cell"
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.userArray.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier(textCellIdentifier, forIndexPath: indexPath) as! SearchUsersRegistrationTableViewCell
let row = indexPath.row
let cellDataParse : PFObject = self.userArray.objectAtIndex(row) as! PFObject
//cell.userImage.image = UIImage(named: usersArr[row])
cell.usernameLabel.text = cellDataParse.objectForKey("_User") as! String
return cell
}
}
I fixed the issue. I needed to cast the index path row in the users array as a PFUser and then cast the user's username property as a String and then set that as the label text.
let row = indexPath.row
var user = userArray[row] as! PFUser
var username = user.username as String
cell.usernameLabel.text = username

Resources