Got a question regarding query from Parse.
I have a list of users on Parse and for every single user, information, like a Timeline, regarding their life events : when was born, what did he do in a certain year, everything displayed in a UITableView.
The thing is that when I press the button for synchronization with Parse, not all data is retrieved. For example, I can get the data for some of them, but for others not.
What could be the reason for this ?
func queryParseForEventsWithCompletionHandler(completionHandler:(success:Bool) -> Void)
{
var query = PFQuery(className:"Event")
query.findObjectsInBackgroundWithBlock
{
(objects: [AnyObject]!, error: NSError!) -> Void in
if error == nil
{
// The find succeeded.
NSLog("Successfully retrieved \(objects.count) events.")
// save parse objects to core data
Event.MR_truncateAll()
for object in objects
{
if object.objectForKey("user") != nil
{
var userEvent = object["user"] as! PFObject
userEvent.fetchIfNeededInBackgroundWithBlock
{(userObj: PFObject!, error: NSError!) -> Void in
self.saveToCoreDataEvent(object as AnyObject, userId: userObj.objectId as NSString)
}
}
else
{
self.saveToCoreDataEvent(object as AnyObject, userId: "")
}
}
completionHandler(success: true)
return
}
else
{
// Log details of the failure
NSLog("Error: %# %#", error, error.userInfo!)
completionHandler(success: false)
return
}
}
}
Related
I want to get all items from my Parse.com table called Sticker, from a particular shop. My Sticker table has a column called shopId. So the obvious solution is this:
//get all stickers from one shop of category dress
var query = PFQuery(className:"Sticker")
query.whereKey("shopId", equalTo: "QjSbyC6k5C")
query.whereKey("category", equalTo: "DR")
query.findObjectsInBackgroundWithBlock {
(objects: [AnyObject]?, error: NSError?) -> Void in
if error == nil {
// The find succeeded.
println("Successfully retrieved \(objects!.count) scores.")
// Do something with the found objects
if let objects = objects as? [PFObject] {
for object in objects {
println(object.objectId)
}
}
} else {
// Log details of the failure
println("Error: \(error!) \(error!.userInfo!)")
}
}
However that causes this error:
error: pointer field shopId needs a pointer value
I have seen a common solution for this seems to be to pass the query the actual object and not a string of the ID. Does this mean I have to first do a separate query to get the specific shop object, and then pass that to my query? Or is there a shorter way?
Here is my attempt to get the shop but it's causing this error:
Can only call -[PFObject init] on subclasses conforming to
PFSubclassing
var query1 = PFQuery(className: "Shop")
var shop1 = PFObject()
query1.getObjectInBackgroundWithId("QjSbyC6k5C") {
(shop: PFObject?, error: NSError?) -> Void in
shop1 = shop!
}
EDIT: So my solution was basically doing what the answer suggested. My code was this (Glamour is the name of the shop):
var shopQuery = PFQuery(className:"Shop")
shopQuery.getObjectInBackgroundWithId("QjSbyC6k5C") {
(glamour: PFObject?, error: NSError?) -> Void in
if error == nil && glamour != nil {
println(glamour)
//get all stickers from one shop of category dress
var query = PFQuery(className:"Sticker")
query.whereKey("shopId", equalTo: glamour!)
query.whereKey("category", equalTo: "DR")
query.findObjectsInBackgroundWithBlock {
(objects: [AnyObject]?, error: NSError?) -> Void in
if error == nil {
// The find succeeded.
println("Successfully retrieved \(objects!.count) scores.")
// Do something with the found objects
if let objects = objects as? [PFObject] {
for object in objects {
println(object.objectId)
}
}
} else {
// Log details of the failure
println("Error: \(error!) \(error!.userInfo!)")
}
}
} else {
println(error)
}
}
I will leave this question here and maybe someone will answer with a comment: Is there any way to get the shop and give it class scope so that we do not have to nest the second query inside the success of the first query? Would that be more elegant?
You need to pass PFObject. change your code with following
PFObject *object = ...
var query = PFQuery(className:"Sticker")
query.whereKey("shopId", equalTo: "QjSbyC6k5C")
query.whereKey("category", equalTo: object);
I'm building an app and at sign up/log in, it will go through the users address book, take the phone numbers, check against phone number column in the User class on Parse and if they aren't friends, then add them.
I have a function in AddressBookHelper.swift to help get the phone numbers:
class AddressBookHelper: NSObject {
let addressBook = AFAddressBookManager()
static var addressBookData = AFAddressBookManager.allContactsFromAddressBook()
static var contactsArray = [String]()
static func getContacts() -> [String] {
var array = [String]()
for contact in addressBookData{
let phoneNumberArray = contact.numbers as! [String]
for number in phoneNumberArray{
array.append(number)
}
}
return array
}
}
Then in ParseHelper.swift I do the check again Parse User class:
static func lookUpUserFromAddressBook(addressBook: [String], completionBlock: PFArrayResultBlock) {
for numbers in addressBook{
let query = User.query()
query!.whereKey("telephone", equalTo:numbers)
query!.findObjectsInBackgroundWithBlock(completionBlock)
}
}
And lastly, when the button is clicked, I add the user as a friend, if not already a friend:
#IBAction func importContacts(sender: AnyObject) {
ParseHelper.lookUpUserFromAddressBook(AddressBookHelper.getContacts()) {
(results: [AnyObject]?, error: NSError?) -> Void in
if error == nil {
if let objects = results as? [PFObject] {
for object in objects {
let userObject = object as! User
self.matchedUsers.append(userObject)
let query = PFQuery(className: "Friends")
query.includeKey("toUser")
query.whereKey("fromUser", equalTo: User.currentUser()!)
query.findObjectsInBackgroundWithBlock {
(objects: [AnyObject]?, error: NSError?) -> Void in
if error == nil {
if (objects!.count == 0) {
ParseHelper.addFollowRelationshipFromUser(fromUser: User.currentUser()!, toUser: userObject, completionBlock: { (success, error) -> Void in
if success{
self.performSegueWithIdentifier("skipped", sender: self)
}
else{
print("Error: \(error!) \(error!.userInfo)")
}
})
}
else{
self.performSegueWithIdentifier("skipped", sender: self)
}
} else {
print("Error: \(error) \(error!.userInfo)")
}
}
}
}
}
else {
print("Error: \(error!) \(error!.userInfo)")
}
}
}
Am I doing this the right way? It works, but the code seems a bit long. Is there an easier way to do this?
Thanks in advance
You should take a look at PFQuery's whereKey:containedIn:. This will return you a list of all users whose phone numbers match any of the numbers you pass in an array. This will greatly reduce the number of queries you need to do to retrieve the user's contacts.
// Find users with any of these phone numbers
let numbers = ["1234567890", "1111111111", "222222222"]
query.whereKey("phoneNumber", containedIn: numbers)
From the Parse iOS Developers Guide:
https://parse.com/docs/ios/guide#queries
If you want to retrieve objects matching several different values, you
can use whereKey:containedIn:, providing an array of acceptable
values. This is often useful to replace multiple queries with a single
query.
You can also create all the follow relationships in one query using PFObject.saveAllInBackground() which takes an array of PFObjects to save.
I want to be able to organize the data i am receiving from parse by creation date, How do i do that?
I looked at the parse docs online, but i could not find anything that said how to query data by creation date. I also saw an answer of stack over flow, but it was in objective-c. Please answer in swift.
Here is the code i am using now to receive my data...
var query = PFQuery(className:"Class Name")
//this is what i tried..
query.orderByDescending("createdAt")
//
query.findObjectsInBackgroundWithBlock {
(objects: [AnyObject]?, error: NSError?) -> Void in
if error == nil {
// The find succeeded.
// Do something with the found objects
if let objects = objects as? [PFObject] {
for object in objects {
self.NameArray.insert(object.valueForKey("Name")! as! String, atIndex: 0)
self.TextArray.insert(object.valueForKey("Text")! as! String, atIndex: 0)
}
}
} else {
// Log details of the failure
self.alert("Error: \(error!.localizedDescription)", Message: "Make sure you have a secure internet connection")
}
dispatch_async(dispatch_get_main_queue()) {
println("Finished importing")
self.collectionView.reloadData()
}
}
How can I wait until data is retrieved from parse.com?
This is the function I have that returns an empty string since the response from parse.com is too slow. If I put a breakpoint inside the success area it will break "long" after the data is needed. I guess there is a way to get the data synchronous so it will wait?
func getObjectId(localPersonId:NSString) -> NSString{
var currentObjectId:NSString = ""
var query = PFQuery(className:"myClass")
query.whereKey("personId", equalTo:localPersonId)
query.whereKey("groupId", equalTo:self.currentGroupId)
query.findObjectsInBackgroundWithBlock {
(objects: [AnyObject]!, error: NSError!) -> Void in
if error == nil {
// should not use a for loop since this should
// only return one row
for object in objects {
currentObjectId = object["objectId"] as NSString
}
} else {
// Log details of the failure
NSLog("Error: %# %#", error, error.userInfo!)
}
}
return currentObjectId
}
In this case the getObjectId function will return an empty string. Anyone?
I realize this is 3 months old but although the Parse docs are incredibly good/useful, there isn't a whole lot out there answering IOS Parse related questions.
This should work. It uses a completion handler, which is a simple way of dealing with this issue.
(for more on completion handlers in asynch context: https://thatthinginswift.com/completion-handlers/ )
func getObjectId(localPersonId:NSString, completionHandler: (currentObjectId: [String]) -> ()){
var currentObjectId:NSString = ""
var query = PFQuery(className:"myClass")
query.whereKey("personId", equalTo:localPersonId)
//query.whereKey("groupId", equalTo:self.currentGroupId)
query.findObjectsInBackgroundWithBlock {
(objects, error) -> Void in
if error == nil {
// should not use a for loop since this should
// only return one row
for object in objects {
completionHandler(currentObjectId: currentObjectId)
}
} else {
// Log details of the failure
NSLog("Error: %# %#", error!, error!.userInfo!)
}
}
}
I have a UICollectionView with a UIRefreshControl. The UIRefreshControl runs a query to get objects from Parse.com. When I perform the refresh by "pulling down" it causes the app to crash and display this message:
fatal error: Cannot index empty buffer
However when I press a button or in the ViewDidLoad to run the same refresh code it does not crash and performs the query as required. Does this mean that there is something wrong with the dragging rather than the refresh code?
Here is the refresh code below (is it to do with the positioning of self.refreshControl.endRefreshing()?)
func refresh(sender:AnyObject)
{
println("Refresh")
self.orderedIdArray = []
self.idArray = []
self.organizerNameArray = []
self.categoryNameArray = []
self.classNameArray = []
var query = PFQuery(className:"Rides")
query.orderByAscending("date")
query.findObjectsInBackgroundWithBlock {
(objects: [AnyObject]!, error: NSError!) -> Void in
if error == nil {
// The find succeeded.
NSLog("Successfully retrieved \(objects.count) scores.")
// Do something with the found objects
for object in objects {
NSLog("%#", object.objectId)
var testId = object.objectId
println(testId)
self.orderedIdArray.append(testId)
var query = PFQuery(className:"Rides")
query.getObjectInBackgroundWithId(testId) {
(gameScore: PFObject!, error: NSError!) -> Void in
if error == nil {
NSLog("%#", gameScore)
//Gets the Values from Parse.com
self.organizerNameString = gameScore["organizer"] as String
self.categoryNameString = gameScore["category"] as String
self.classNameString = gameScore["class"] as String
self.organizerNameArray.append(self.organizerNameString)
self.categoryNameArray.append(self.categoryNameString)
self.classNameArray.append(self.classNameString)
self.idArray.append(object.objectId)
NSLog("%#", self.idArray)
} else {
println("Do not add to the array")
}
}
} else {
NSLog("%#", error)
}
self.collectionView?.reloadData()
}
}
} else {
// Log details of the failure
NSLog("Error: %# %#", error, error.userInfo!)
}
self.refreshControl.endRefreshing()
NSLog("Ordered: %#", self.orderedIdArray)
}
println("Completed the query")
}