SWIFT: Parse column is not appending into array - ios

I'd like to append the 'userVotes' column in the following parse table into an array using Swift -
Here is my code -
import UIKit
import Parse
class MusicPlaylistTableViewController: UITableViewController {
var usernames = [String]()
var songs = [String]()
var voters = [String]()
var numVotes = 0
override func viewDidLoad() {
super.viewDidLoad()
tableView.separatorColor = UIColor.grayColor()
let 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.voters.removeAll()
for object in objects {
let username = object["username"] as? String
self.usernames.append(username!)
let track = object["song"] as? String
self.songs.append(track!)
let title = object["userVotes"]! as? String
self.voters.append(title!)
print("Array: \(self.voters)")
}
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.username.text = usernames[indexPath.row]
cell.songTitle.text = songs[indexPath.row]
cell.votes.text = "\(numVotes)"
cell.selectionStyle = UITableViewCellSelectionStyle.None
return cell
}
override func tableView(tableView: UITableView, didDeselectRowAtIndexPath indexPath: NSIndexPath) {
}
}
I would like the parse array column to append as follows -
[["user1,"user5,"user9"],["user1,"user2,"user3"],["user4,"user5,"user6"],...]
At this point, I'm getting the following runtime error - fatal error: unexpectedly found nil while unwrapping an Optional value

Since each object that is in your "userVotes" is an array and your you've declared
var voters = [String]()
which is not right because you're saying that there will be one element being appended which is not the case.
So, you should declare voters as...
var voters = Array<Array<String>>()
then as you are downloading it,
for object in objects {
let title = object["userVotes"]! as? [String]
self.voters.append(title!)
print("Array: \(self.voters)")
}

Related

Populate an array for the tableView section and the tableView cell, swift

I am trying to implement a TableView like Instagram with one row per section.
I would like to populate two arrays :
first sectionArray to get the row data in function of the section
and object to get the Name of the section.
But when I try to populate sectionArray, I get an error :
"fatal error: Array index out of range"
Do you have an idea of how to fix it??
Thanks!
import UIKit
import ParseUI
import Parse
class TableView: UIViewController, UITableViewDelegate, UITableViewDataSource, CLLocationManagerDelegate {
#IBOutlet weak var tableView : UITableView?
var sectionArray : [[PFFile]] = []
override func viewDidLoad() {
super.viewDidLoad()
self.loadCollectionViewData()
}
var object = [PFObject]()
func loadCollectionViewData() {
let query = PFQuery(className: "Myclass")
// Fetch data from the parse platform
query.findObjectsInBackgroundWithBlock {
(objects: [PFObject]?, error: NSError?) -> Void in
// The find succeeded now rocess the found objects into the countries array
if error == nil {
// Clear existing country data
self.object.removeAll(keepCapacity: true)
// Add country objects to our array
if let objects = objects as [PFObject]? {
self.object = Array(objects.generate())
let index = self.object.count as Int
print (index)
for i in 1...index {
//error here!
if let finalImage = self.object[i]["image"] as? [PFFile]
{
self.sectionArray[i] = finalImage
print(self.sectionArray[i])
}
}
}
// reload our data into the collection view
self.tableView?.reloadData()
} else {
// Log details of the failure
print("Error: \(error!) ")
}
}
}
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return sectionArray.count
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return sectionArray[section].count
}
func tableView(tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
if section < self.object.count {
if let namelabel = object[section]["Name"] as? String {
return namelabel
}
}
return nil
}
func tableView(tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
return 30
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var cell = tableView.dequeueReusableCellWithIdentifier("Cell") as! ListControllerViewCell!
if cell == nil
{
cell = ListControllerViewCell(style: UITableViewCellStyle.Default, reuseIdentifier: "Cell")
}
if let finalImage = sectionArray[indexPath.section][indexPath.row] as? PFFile //object[indexPath.row]["image"] as? PFFile
{
finalImage.getDataInBackgroundWithBlock{(imageData: NSData?, error: NSError?) -> Void in
if error == nil
{
if let imageData = imageData
{
cell.ImagePromo!.image = UIImage(data:imageData)
}
}
}
if let CommentLabel = sectionArray[indexPath.section][indexPath.row]
//object[indexPath.row]["Comment"] as? String
{
cell.CommentLabel!.text = CommentLabel
cell.CommentLabel!.adjustsFontSizeToFitWidth = true
}
return cell;
}
}
You have a problem in your for in loop :
You should start at 0, not 1 so your call to the loop looks like :
for i in 0..<index
This is the "danger" with for-in loops compared to C-style loops. You are looping the correct number of times, but you exceed your array size by 1 because you are starting at the wrong index.
Try adding Exception Breakpoint to catch the error location exactly,
Also edit your datasource as,
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
if(sectionArray.count != 0) {
return sectionArray.count
} else {
return 0;
}
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if(sectionArray.count < section) {
return sectionArray[section].count
} else {
return 0;
}
}

swift parsing CSV file from API does not separate with the delimiter

I'm trying to pass the data into the cells of a tableView. The networking communication works because The list of items appear in the first cell.
For example the list come like: sensor1, sensor2, sensor3,....
but it should be like :
sensor1
sensor2
...
this is how I'm parsing the CSV file
struct ParseCVS {
func parseURL (contentsOfURL: NSURL, encoding: NSStringEncoding) -> ([String])?{
let rowDelimiter = ","
var nameOfSensors:[String]?
do {
let content = try String(contentsOfURL: contentsOfURL, encoding: encoding)
print(content)
nameOfSensors = []
let columns:[String] = content.componentsSeparatedByCharactersInSet(NSCharacterSet.newlineCharacterSet()) as [String]
for column in columns {
let values = column.componentsSeparatedByString(rowDelimiter)
if let nameOfSensor = values.first {
nameOfSensors?.append(nameOfSensor)
}
}
}
catch {
print(error)
}
return nameOfSensors
}
}
and this is my TableViewController
class TableViewController: UITableViewController {
// Array which will store my Data
var nameOfSensorsList = [String]()
override func viewDidLoad() {
super.viewDidLoad()
guard let wetterURL = NSURL(string: "http://wetter.htw-berlin.de/phpFunctions/holeAktuelleMesswerte.php?mode=csv&data=1")
else {
return
}
let parseCSV = ParseCVS()
nameOfSensorsList = parseCSV.parseURL(wetterURL, encoding: NSUTF8StringEncoding)!
tableView.estimatedRowHeight = 100.0
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
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 {
return nameOfSensorsList.count
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as! MenuTableViewCell
cell.nameLabel?.text = nameOfSensorsList[indexPath.row]
return cell
}
}
if someone have any ideas I would really appreciate it.
You've forgotten to iterate through an array of "values".
Try something like this:
for column in columns {
let values = column.componentsSeparatedByString(rowDelimiter)
print(values.count)
for value in values {
nameOfSensors?.append(value)
}
}

Why does my tableview return the same Parse image for every cell?

I have my tableview returning titles, their descriptions and now I am trying to return images. It currently returns only one image for all of my cells. Is this because I'm storing it in a UIImage?
Here's my code:
import UIKit
import Parse
import Bolts
import ParseUI
class YourEvents: UIViewController, UITableViewDataSource, UITableViewDelegate {
#IBOutlet weak var tableView: UITableView!
var currentuser = PFUser.currentUser()?.username
//array
var testArray = [String]()
var testdecr = [String]()
var image = UIImage()
// var imagestored = UIImage()
override func viewDidLoad() {
super.viewDidLoad()
var query = PFQuery(className:"Companies")
let pUserName = PFUser.currentUser()?["username"] as? String
query.whereKey("createdby", equalTo:"\(pUserName)")
// let runkey = query.orderByAscending("companyname")
query.findObjectsInBackgroundWithBlock{
(objects: [PFObject]?, error: NSError?) -> Void in
if error == nil {
//do something with the found objects
if let objects = objects as [PFObject]! {
for object in objects {
let load = object.objectForKey("companyname") as! String
self.testArray .append(load)
print(self.testArray)
let load2 = object.objectForKey("companydescription") as! String
self.testdecr.append(load2)
print(self.testdecr)
if let userImageFile = object["imagefile"] as? PFFile {
userImageFile.getDataInBackgroundWithBlock {
(imageData: NSData?, error: NSError?) -> Void in
if error == nil {
if let imageData = imageData {
self.image = UIImage(data:imageData)!
print("done!")
self.do_table_refresh()
}
}
}
}
}
}
} else {
//log details of failure
print("Error: \(error!) \(error?.userInfo) ")
}
}
// reload UIViewController and UITabkeView
sleep(3)
do_table_refresh()
}
func do_table_refresh () {
dispatch_async(dispatch_get_main_queue(), {
self.tableView.reloadData()
return
})
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return testArray.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("yourstartups", forIndexPath: indexPath) as! YourStartupsCell
cell.lbTitle!.text = self.testArray[indexPath.row]
cell.lbDescription!.text = self.testdecr[indexPath.row]
cell.logo!.image = self.image
return cell
}
}
I would recommend making an array of PFImage objects, and then in your table view delegate method you can simply access the element at the current row in your index path. Right now your method to get the data is being called once and therefore setting your image to the last fetched object, but since the tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) is being called each time a cell is loaded, you need to keep the images in an array, as you are doing with the text labels.

iOS Swift get JSON data into tableView

I have a JSON Data which I want to get into UITable. The data is dynamic so table should update every time view loads. Can anyone help?
{
data = (
{
id = 102076330;
name = "Vicky Arora";
}
)
}
try this....
When you receive response,get the whole array of dictionary
if let arr = response["data"] as? [[String:String]] {
YourArray = arr
// Define YourArray globally
}
Then in tableview cell,cellForRowAtIndexPath method
if let name = YourArray[indexpath.row]["name"] as? String{
label.text = name
}
//Same You can done with id
And don't forget to set number of rows
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// #warning Incomplete method implementation.
// Return the number of rows in the section.
return YourArray.count
}
Try this one. But this sample i'm using Alamofire and SwitfyJSON. Import it using CocoaPod.
import UIKit
import Alamofire
class TableViewController: UITableViewController{
var users: [JSON] = []
override func viewDidLoad() {
super.viewDidLoad()
Alamofire.request(.GET, "http://xxxxx/users.json").responseJSON { (request, response, json, error) in
if json != nil {
var jsonObj = JSON(json!)
if let data = jsonObj["data"].arrayValue as [JSON]?{
self.users = data
self.tableView.reloadData()
}
}
}
}
// 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.
return users.count
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("UserCell", forIndexPath: indexPath) as! UITableViewCell
let user = users[indexPath.row]
if let idLabel = cell.viewWithTag(100) as? UILabel {
if let id = user["id"].string{
idLabel.text = id
}
}
if let nameLabel = cell.viewWithTag(101) as? UILabel {
if let name = user["name"].string{
nameLabel.text = name
}
}
return cell
}
}
If you are up to using Core Data, I would suggest using the NSFetchedRequest.
Every time you are getting the data from the server, save it to Core data, and that will automatically update the table view.
Here is a tutorial from Ray Wenderlich

Swift Converting PFQuery to String Array for TableView

I am trying to query all of the Parse users in my database and then display each individual user in their own cell in a tableview. I have set up my tableview, but I'm stuck on saving the user query to a string array that can be used within the tableview. I have created a loadParseData function that finds the objects in the background and then appends the objects queried to a string array. Unfortunately I am given an error message on the line where I append the data.
Implicit user of 'self' in closure; use 'self.' to make capture semantics explicit' This seems to me that it is suggestion that I use self. instead of usersArray. because this is within a closure, but I'm given another error if I run it that way, *classname* does not have a member named 'append'
Here is my code:
import UIKit
class SearchUsersRegistrationViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
var userArray = [String]()
#IBOutlet var tableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
tableView.delegate = self
tableView.dataSource = self
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func loadParseData(){
var query : PFQuery = PFUser.query()
query.findObjectsInBackgroundWithBlock {
(objects:[AnyObject]!, error:NSError!) -> Void in
if error != nil{
println("\(objects.count) users are listed")
for object in objects {
userArray.append(object.userArray as String)
}
}
}
}
let textCellIdentifier = "Cell"
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
//return usersArray.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier(textCellIdentifier, forIndexPath: indexPath) as SearchUsersRegistrationTableViewCell
let row = indexPath.row
//cell.userImage.image = UIImage(named: usersArray[row])
//cell.usernameLabel?.text = usersArray[row]
return cell
}
}
The problem is that userArray is an NSArray. NSArray is immutable, meaning it can't be changed. Therefore it doesn't have an append function. What you want is an NSMutableArray, which can be changed and has an addObject function.
var userArray:NSMutableArray = []
func loadParseData(){
var query : PFQuery = PFUser.query()
query.findObjectsInBackgroundWithBlock {
(objects:[AnyObject]!, error:NSError!) -> Void in
if error == nil {
if let objects = objects {
for object in objects {
self.userArray.addObject(object)
}
}
self.tableView.reloadData()
} else {
println("There was an error")
}
}
}
Also, because objects are returned as 'AnyObject' you will have to cast them as PFUsers at some point in order to use them as such. Just something to keep in mind
For getting the user's username and displaying it
// Put this in cellForRowAtIndexPath
var user = userArray[indexPath.row] as! PFUser
var username = user.username as! String
cell.usernameLabel.text = username

Resources