Global array only returns 0 - ios

I have instantiated a global array called array and try append the values from dictionary to the array. I have successfully copied the values from the dictionary to the array but it seems to only locally. I am not sure where I have done wrong. Please help me figure it out. Here's the code :
class StudentTableViewController: UITableViewController {
var dict = Dictionary<String, String> ()
var array = [Dictionary<String, String>] ()
// Student
override func viewDidLoad() {
super.viewDidLoad()
queryData()
}
func queryData ()-> (Int, [Dictionary<String, String>]) {
var userQuery = PFUser.query()
//var arr = []
var count : Int
count = 0
userQuery?.whereKey("Type", equalTo:"student")
userQuery?.findObjectsInBackgroundWithBlock({ (objects: [AnyObject]?, error: NSError?) -> Void in
for object in objects! {
self.dict["firstName"] = object["firstName"] as! NSString as String
self.dict["lastName"] = object["lastName"] as! NSString as String
self.dict["contact"] = object["contact"] as! NSString as String
self.array.append(self.dict)
}
println(self.array)
count = self.array.count
})
return(self.array.count, self.array)
// returns 0
// return empty array
}
Here, self.array.count return 0 but I want to return the count of the dictionary members and the self.array only return empty array where I want it to return the dictionary.
I have been stuck on this for a while, I am not sure why it doesn't want to be global
Thanks

findObjectsInBackgroundWithBlock is asynchronous, so when your method returns, the block hasn't even run yet. Instead, you need to call something in your block with the results. Here is an example of how to do this by passing a completion block.
override func viewDidLoad() {
super.viewDidLoad()
queryData {
// update view
}
}
func queryData(completionHandler: () -> Void) {
var userQuery = PFUser.query()
var count : Int
count = 0
userQuery?.whereKey("Type", equalTo:"student")
userQuery?.findObjectsInBackgroundWithBlock({ (objects: [AnyObject]?, error: NSError?) -> Void in
for object in objects! {
self.dict["firstName"] = object["firstName"] as! NSString as String
self.dict["lastName"] = object["lastName"] as! NSString as String
self.dict["contact"] = object["contact"] as! NSString as String
self.array.append(self.dict)
}
println(self.array)
count = self.array.count
dispatch_async(dispatch_get_main_queue) {
completion()
}
})
return(self.array.count, self.array)
}

Related

Retrieve data from first only item in for loop

I have a query that gets objects from the server I'm then reducing the number of objects by matching "packName" to "className" which should just give me the children of "packName".
from this i am populating an array of struct items and pulling out the data for the first index of the array.
this is fine but I'm just a bit concerned that if the number of children increases this may slow processing down. so i was wondering if there was a way to just retrieve the first item of the for loop, which is all I'm after as the query has been sorted in ascending order.
this is the function code below.
class func createHistory(packName: String, completeBlock: ((Bool) -> Void)? = nil) {
struct initialDataStruct {
var packNameStruct : String
var packIdStruct : String
var partNameStruct : String
var partIdStruct : String
var partIndexStruct : Int
}
var initialDataArray = [initialDataStruct]()
let historyClass = PFObject(className: packName)
let query = PFQuery(className: "Part")
query.includeKey("fromPack")
query.order(byAscending: "partName")
query.fromLocalDatastore()
query.findObjectsInBackground { (objects, error) in
if error != nil {
print(error!)
}
else if let parts = objects {
for object in parts {
// if the fromPack column has data
if let fromPack = object.object(forKey: "fromPack") as? PFObject {
// create the class name from the pack name
if let className = (fromPack.object(forKey: "packName") as? String) {
// packName was sent from JVC
// this will limit array items to how ever many children packName has
if packName == className {
// because its sorted could probably just get the first item here
let packName = fromPack.object(forKey: "packName") as! String
let packId = fromPack.objectId as String!
let partName = object.object(forKey: "partName") as! String
let partId = object.objectId as String!
let partIndex = 0
initialDataArray.append(initialDataStruct(packNameStruct: packName,
packIdStruct: packId!,
partNameStruct: partName,
partIdStruct: partId!,
partIndexStruct: partIndex))
}
}
}
} // for
historyClass.add(initialDataArray[0].packNameStruct, forKey: "packName")
historyClass.add(initialDataArray[0].partIdStruct, forKey: "packId")
historyClass.add(initialDataArray[0].partNameStruct, forKey: "partName")
historyClass.add(initialDataArray[0].partIndexStruct, forKey: "partIndex")
print(historyClass)
PFObject.pinAll(inBackground: [historyClass])
}
} // query
}

Why is the app crashing when I try to append an array?

I am importing an array from parse, and I want to add that array to an array of arrays, but the app crashes when it tries to append the imported array. Why is that occurring and how can I fix it? Crash error is Thread 1: EXC_BAD_INSTRUCTION(code=EXC_I386_INVOP, subcode=0x0 I commented the append line and it does not crash, so it has to be that line.
var animalarray: [[String]] = []
let query = PFQuery(className: "animals")
query.findObjectsInBackgroundWithBlock { (objects: [PFObject]?, error: NSError?) -> Void in
if error == nil{
for object in objects!{
if let animalss = object["CoordinateTest"]{
print("coord \(animalss)")
self.animalarray.append(animalss as! [String])//crashes here
}
}
}
}
You should create a method that retrieves the data, and use queries to specify what you want. Also you should create a temporary variable to hold to retrieved data and append that variable to the array.
Ex.)
var animalsArray: [String] = []
func retrieveData(){
let query = PFQuery(className: "animals")
query.whereKey("Key", equalTo: object)
query.orderByDescending("createdAt")
query.findObjectsInBackgroundWithBlock {
(object:[PFObject]?, error:NSError?) -> Void in
if ( error != nil ){
print(error?.localizedDescription, error?.userInfo)
} else {
for temp: PFObject in object! {
let animals: String = temp["CoordinateTest"] as! String
self.animalsArray.append(animals!)
}
}
}
}

Appending into an array from completion block

I am attempting to append the results of the parse query into usersData
struct Data {
var FirstName:String!
var LastName:String!
var Gender:String!
var Age:String!
}
In the class I have
var usersData = [Data]()
I am using this to
func parseUsersData(completionHandler: [Data] -> Void) {
var usersDataArray = [Data]()
let query = PFQuery(className: "_User")
query.fromLocalDatastore()
query.findObjectsInBackgroundWithBlock { (objects, error) -> Void in
if error == nil {
if let user = objects as? [PFObject]! {
for object in user! {
var singleData = Data()
singleData.FirstName = object["firstName"] as! String
singleData.LastName = object["lastName"] as! String
singleData.Gender = object["gender"] as! String
singleData.Age = object["age"] as! String
usersDataArray.append(singleData)
}
}
completionHandler(usersDataArray)
}
}
}
finally, I am trying to do this:
Edit: To clarify, I need to pass the data from the queries, userDataArray, into the array usersData.
parseUsersData { (usersDataArray) -> Void in
usersData.append(usersDataArray)
}
The error I am getting is
Cannot convert value of type '[Data]' to expected argument type 'Data'
In your last code block you seem to appending a Data array to a Data object usersData.append(usersDataArray) which causes error I think. Did you mean to write usersDataArray.append(usersData) which makes a lot more sense?
You are attempting to add an array of Data to an array that is looking for Data Objects. Add a new struct that handles your Data Array and then change the usersData to look for DataArray's:
struct DataArray {
var array = [Data]()
}
And change the line:
var usersData = [DataArray]()
usersDataArray is an array. To add an array to an other array, prefer appendContentsOf :
usersData.appendContentsOf(usersDataArray)

how to retrive data from a user pointer on Parse using swift

On Parse I have users with Facebook profile and Email login profile. So I want to bury for users data in my twitter-like app.
In my "messages" class on Parse I have column "sender" that contains pointers to parse users.
I just want to retrive and show the name of users in class "messages" contained in the column "sender" wich contains pointers to PFUsers of which I need data for keys
"first_name"
"last_name"
"profile_picture"
How can I retrive their data like name and image in order to show them in a tableview?
these are the declarations of my arrays:
var sendersArray : [String] = []
var picturesArray : [NSData] = []
maybe I could use something like this tuple, but I can't understand how to grab data from pointers
for user in list {
let firstName = "fist_name"
let lastName = "last_name"
let oProfileImage = NSData() //"image_profile" as! NSData
otherUsers.append((oName: firstName, oLastName: lastName, oImageProfle: oProfileImage))
}
version - 1:
I started with printing the whole pf object
//******************************************************
func theSearch() {
let theSearchQuery = PFQuery(className: "Messages")
theSearchQuery.findObjectsInBackgroundWithBlock({
(objects : [AnyObject]?, error : NSError?) -> Void in
for object in objects! {
let theName = object.sender!
print(object)
print(theName)
sendersArray.append(theName)
let profilePicture = object["profile_pic"] as! PFFile
picturesArray.append(profilePicture)
}
self.tableView.reloadData()
})
}
//*******************************************************
version - 2:
then, found this solution, but still, doesn't
func theSearch() {
let theSearchQuery = PFQuery(className: "Messages" )
theSearchQuery.includeKey("sender")
theSearchQuery.findObjectsInBackgroundWithBlock({
(objects : [AnyObject]?, error : NSError?) -> Void in
for object in objects! {
let theName = object.sender!["first_name"] as? String
print(object)
print(theName)
sendersArray.append(theName)
let profilePicture = object["profile_pic"] as! PFFile
picturesArray.append(profilePicture)
}
self.tableView.reloadData()
})
}
errors:
seems to be a problem with sender, maybe I shouldn't use it
thanks in advance
let theName = object.objectForKey("sender")!.objectForKey("first_name") as! String
Complete Code:
func theSearch() {
let theSearchQuery = PFQuery(className: "Messages")
theSearchQuery.includeKey("sender")
theSearchQuery.findObjectsInBackgroundWithBlock({
(objects : [AnyObject]?, error : NSError?) -> Void in
for object in objects! {
let theName = object.objectForKey("sender")!.objectForKey("first_name") as! String
print(object)
print(theName)
self.sendersArray.append(theName)
let profilePicture = object["profile_picture"] as! PFFile
self.picturesArray.append(profilePicture)
}
self.tableView.reloadData()
})
}
Also, your picturesArray should be of type PFFile, like this:
var picturesArray = [PFFile]()
NOT NSData. change that at the top of your class.
-----EDIT------:
If you want to retrieve an image from a parse query, do this:
1) at the top of your class, declare the following arrays to store the results:
// your images will be stored in the file array
var fileArray = [PFFile]()
// your first and last names will be stored in String Arrays:
var firstNameArray = [String]()
var lastNameArray = [String]()
2) perform the query:
let query1 = PFQuery(className: "_User")
query1.orderByDescending("createdAt")
query1.findObjectsInBackgroundWithBlock({
(objects : [AnyObject]?, error : NSError?) -> Void in
if error == nil {
for x in objects! {
let firstName = x.objectForKey("first_name") as! String
let lastName = x.objectForKey("last_name") as! String
self.firstNameArray.append(firstName)
self.lastNameArray.append(lastName)
if x.objectForKey("profile_picture") as? PFFile == nil {
print("do nothing cause it's nil")
}
else {
let file:PFFile = x.objectForKey("profile_image") as! PFFile
self.fileArray.append(file)
}
}
self.tableView.reloadData()
}
})
Note I am using Swift 2 and Xcode 7. Syntax is slightly different in Xcode 6.4 and Swift 1.2.

Swift Parse - local datastore items not appearing in tableView

This is a followup of my question from yesterday yesterdays post
I have successfully saved and object in the local datastore using parse, and and trying to add that object to an array to store them so i can display the contents in a table view. the query is running fine, but it appears to me that nothing is being appended into the array, so nothing shows in the table view. here's my code.
localData.swift file
import Foundation
struct localData {
var date: String!
var latt: NSNumber!
var lattDelta: NSNumber!
var locality: String!
var longi: NSNumber!
var longiDelta: NSNumber!
var name: String!
var note: String!
}
I then declare this globally:
var arrayToPopulateCells = [localData]()
this is my parse query:
func performQuery() {
let query = PFQuery(className: "ParseLighthouse")
query.fromLocalDatastore()
query.whereKey("User", equalTo: PFUser.currentUser()!)
query.findObjectsInBackgroundWithBlock { (objects, error) -> Void in
if error == nil {
// The find succeeded.
println("Successfully retrieved \(objects!.count) lighthouses.")
// Do something with the found objects
if let light = objects as? [PFObject] {
for object in light {
// println(object.objectId)
// println(object.objectForKey("Name"))
// println(object.objectForKey("Locality"))
var singleData = localData()
singleData.name = object["Name"] as! String
singleData.note = object["Note"] as! String
singleData.date = object["Date"] as! String
singleData.latt = object["Latt"] as! NSNumber
singleData.longi = object["Longi"] as! NSNumber
singleData.lattDelta = object["LattDelta"] as! NSNumber
singleData.longiDelta = object["LongiDelta"] as! NSNumber
singleData.locality = object["Locality"] as! String
self.arrayToPopulateCells.append(singleData)
}
}
} else {
// Log details of the failure
println("Error: \(error!) \(error!.userInfo!)")
}
}
}
in my table code:
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return arrayToPopulateCells.count
}
and
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
// var lighthouse = self.lighthouses[indexPath.row]
var data = self.arrayToPopulateCells[indexPath.row]
//setting the prototype cell to link with the identifier set in attributes earlier.
let cell = tableView.dequeueReusableCellWithIdentifier("locationCell") as! lighthouseCell
let row = indexPath.row
cell.cellName.text = data.name
cell.cellPlace.text = data.locality
// cell.cellCoordinates.text = "\(lighthouse.latt)" + ", " + "\(lighthouse.longi)"
// cell.cellNote.text = lighthouse.note
cell.cellDate.text = "\(data.date)"
return cell
}
so im not sure what i'm doing wrong, but it seems that the query is working but nothing is going into the array. any ideas?
i do want to note that the parse object is created on lets say viewcontroller #2, and the query is run on viewcontroller #1 where the table view is. does this make a difference? should i run the query and try to append right after the object is made on the same controller?
I think your problem is you need to call
self.tableView.reloadData()
outside the for object in light { loop
I think your data is being added to the array ok, its just the table view needs to know when its done.
EDIT***
func performQuery() {
let query = PFQuery(className: "ParseLighthouse")
query.fromLocalDatastore()
query.whereKey("User", equalTo: PFUser.currentUser()!)
query.findObjectsInBackgroundWithBlock { (objects, error) -> Void in
if error == nil {
// The find succeeded.
println("Successfully retrieved \(objects!.count) lighthouses.")
// Do something with the found objects
if let light = objects as? [PFObject] {
for object in light {
var singleData = localData()
singleData.name = object["Name"] as! String
singleData.note = object["Note"] as! String
singleData.date = object["Date"] as! String
singleData.latt = object["Latt"] as! NSNumber
singleData.longi = object["Longi"] as! NSNumber
singleData.lattDelta = object["LattDelta"] as! NSNumber
singleData.longiDelta = object["LongiDelta"] as! NSNumber
singleData.locality = object["Locality"] as! String
self.arrayToPopulateCells.append(singleData)
}
self.tableView.reloadData()
}
} else {
// Log details of the failure
println("Error: \(error!) \(error!.userInfo!)")
}
}
}

Resources