I've been able to save successfully to Parse via Swift, but am having trouble retrieving data (and all of the tutorials on retrieving seem to be for Obj-C).
Here's my code (with Id's redacted).
Parse.setApplicationId("XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", clientKey: "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX")
var query = PFQuery(className: "EventObject")
query.getObjectInBackgroundWithId(objectId: String!) {
(event: PFObject!, error: NSError!) -> Void in
if error == nil {
println(event)
} else {
println(error)
}
}
I have 4 records in this class right now, but if I want to pull the data for all of them, how do I get the Object using the ID if I'm not sure what the IDs are? I'm assuming I can access them sequentially as an array, but I'm not quite clear how to do that, and am confused, as the only command I know to retrieve appears to require knowing the ID.
Thanks for any help!
The official parse documentation explains how to make queries - there is sample code in swift.
In your case you have to use findObjectsInBackgroundWithBlock:
var query = PFQuery(className:"EventObject")
query.findObjectsInBackgroundWithBlock { (objects: [AnyObject]!, error: NSError!) -> Void in
if error == nil {
for object in objects {
// Do something
}
} else {
println(error)
}
}
which, if successful, provides to the closure an array of objects matching the query - since there's no filter set in the query, it just returns all records.
Swift 2.1 Update
func fetchFromParse() {
let query = PFQuery(className:"Your_Class_Name")
query.findObjectsInBackgroundWithBlock { (objects, error) -> Void in
if error == nil {
for object in objects! {
// Do something
}
} else {
print(error)
}
}
}
Here is the code for fetch objects in Swift3.0.
let query = PFQuery(className: "Your_Class_Name")
query.findObjectsInBackground { (objects, error) in
if error == nil {
}
else {
}
}
Retrive Data from parse: swift 3
let adventureObject = PFQuery(className: "ClassName")
adventureObject.addAscendingOrder("objectId")
var objectID: String = String()
adventureObject.findObjectsInBackground(block: { (Success, error) in
})
Related
I have a function to check whether an account already exists in the firestore database so that the user can register for one. I have an bool exists to return whether the account exists or not but the code in getDocument() is not executing and assigning the values properly.
func checkAccountExists(username: String) -> Bool {
let docRef = accountsRef!.document(username)
var exists: Bool!
docRef.getDocument { (document, error) in
if let document = document, document.exists {
exists = true
} else {
exists = false
}
}
return exists //Unexpectedly found nil error
}
Not only does Doug correctly point out that the function is async, in Swift, you should not attempt a function (or a computed property) that returns an async value. Instead, consider a function with an async completion that passes the value as an argument.
func checkAccountExists(username: String, completion: #escaping (_ exists: Bool) -> Void) {
accountsRef!.document(username).getDocument { (document, error) in
if let document = document,
document.exists {
completion(true)
} else {
if let error = error {
print(error)
}
completion(false)
}
}
}
Usage
checkAccountExists(username: someUsername) { (exists) in
if exists {
print("user exists")
} else {
print("user doesn't exist or there was an error")
}
}
However, since the database could return an error (even if the user exists), consider returning a Result instead of a Bool. But if you just want a pass/fail mechanism that doesn't decipher between errors and a user truly not existing, this will work.
I have an array of appointments and I'm trying to grab all of the photos for these appointments from our windows azure blob storage. First, I want to get the list of blobs with the associated appointmentId so I can download and store them properly afterwards.
I'm using PromiseKit but I'm not at all sure about how to use PromiseKit in a loop:
for appointment in appointments {
// Get blobs
}
Here's my code so far. Any help is greatly appreciated!
func getBlobsPromise(appointmentId: Int32) -> Promise<[BlobDownload]> {
return Promise { seal in
var error: NSError?
var blobDownloads = [BlobDownload]()
container = AZSCloudBlobContainer(url: URL(string: containerURL)!, error: &error)
if ((error) != nil) {
print("Error in creating blob container object. Error code = %ld, error domain = %#, error userinfo = %#", error!.code, error!.domain, error!.userInfo)
seal.reject(error!)
}
let prefix: String = "AppointmentFiles/\(appointmentId)"
container?.listBlobsSegmented(with: nil, prefix: prefix, useFlatBlobListing: true, blobListingDetails: AZSBlobListingDetails(), maxResults: 150) { (error : Error?, results : AZSBlobResultSegment?) -> Void in
if error != nil {
seal.reject(error!)
}
for blob in results!.blobs!
{
let blobInfo = blob as! AZSCloudBlob
if blobInfo.blobName.lowercased().contains("jpg") || blobInfo.blobName.lowercased().contains("jpeg") {
let blobDownload: BlobDownload = BlobDownload(appointmentId: Int(jobId), blob: blobInfo)
blobDownloads.append(blobDownload)
}
}
seal.fulfill(blobDownloads)
}
}
}
That returns the blobs as expected but I want to get all of the blobs for all of the appointments before proceeding. Here's what I tried (among other things):
func getBlobsForAllJobs(appointmentIds: [Int32]) -> Promise<[BlobDownload]> {
return Promise { seal in
let count = appointmentIds.count - 1
let promises = (0..<count).map { index -> Promise<[BlobDownload]> in
return getBlobsPromise(agencyCode: agencyCode, appointmentId: appointmentIds[index])
}
when(fulfilled: promises).then({ blobDownloads in
seal.fulfill(blobDownloads)
})
}
}
EDIT 1
I solved this using a DispatchGroup and completion handler. Here's the code in case someone is interested. If there are alternate (better) ways of doing this I'd love to hear them. I'm a c# guy just getting into Swift.
func getBlobsToDownload(appointmentIds: [Int32], completion: #escaping ([BlobDownload]) -> Void) {
var myBlobsToDownload = [BlobDownload]()
let myGroup = DispatchGroup()
for apptId in appointmentIds {
myGroup.enter()
getBlobs(appointmentId: apptId) { (blobDownloads) in
print("Finished request \(apptId)")
print("Blobs fetched from apptId \(apptId) is \(blobDownloads.count)")
for blobDownload in blobDownloads {
myBlobsToDownload.append(blobDownload)
}
myGroup.leave()
}
}
myGroup.notify(queue: .main) {
print("Finished all requests.")
completion(myBlobsToDownload)
}
}
func setExpenses(){
FirebaseFunctions().retrieve(from: .expense, username: username as! String, returning: Expenses.self) { (expenses) in
self.expenses = expenses
}
}
I currently have a firebase query as seen above which retrieves a list of expenses from a cloud firestore database. However, when I run the function bellow and try and print the array, I get a result of the array being empty. I don't understand why the query isn't being able to execute correctly. I have the same code in another view controller, and it works fine which makes me think that it is something to do with the timing. But can somebody please help me to solve this issue?
public func getCollectionExpenses(collection: String, completionHandler: #escaping([[Expenses]], [String]) -> Void){
setExpenses()
print(expenses)
print("hello")
for eachExpense in expenses{
if eachExpense.collection == collection{
expensePerCollection.append(eachExpense)
}
}
Here is the code for the retrieve function, just in case
func retrieve<T: Decodable>(from collectionReference:FIRCollectionReference, username:String, returning objectType: T.Type, completion: #escaping (([T]) -> Void)) {
referenceSub(to: collectionReference, username: username).addSnapshotListener { (snapshot, _) in
guard let snapshot = snapshot else { return }
do {
var objects = [T]()
for document in snapshot.documents {
let object = try document.decode(as: objectType.self)
objects.append(object)
}
completion(objects)
} catch {
print(error)
}
}
}
Where are you setting snapshot.documents? Looks like you need to set in then iterate.
After updating to iOS 10 I would always get this object not found error whenever I try to update a PFObject on the parse heroku server. I have been researching and have tried out what many people have suggested turning on keychain sharing on capabilities. But, still no sign of working.
Some codes I'm using:
let publishQuery = PFQuery(className: "allPosts")
publishQuery.whereKey("objectId", equalTo: objectIdToPublish)
publishQuery.findObjectsInBackground { (objects, error) -> Void in
if let objects = objects {
for object in objects {
publishQuery.getObjectInBackground(withId: object.objectId!, block: { (objectToPublish, error) -> Void in
if error == nil {
let postAcl = PFACL(user: PFUser.current()!)
postAcl.getPublicReadAccess = true
postAcl.getPublicWriteAccess = true
objectToPublish!.acl = postAcl
objectToPublish!["isItPublished"] = true
objectToPublish?.saveInBackground(block: { (success, error) -> Void in
if error == nil {
self.publishedOrNot[((cellIndexPath as NSIndexPath?)?.row)!] = true
self.myTableView.reloadData()
} else {
self.displayAlert("Sth's wrong", message: "Please try again")
print(error)
}
})
}
})
}
}
}
This is the error I'm getting printed in the logs :
2016-10-22 19:10:39.740 Pufff[609:9898] [Error]: Object not found. (Code: 101, Version: 1.13.0)
Optional(Error Domain=Parse Code=101 "Object not found." UserInfo={code=101,
error=Object not found., temporary=0, NSLocalizedDescription=Object not found.})
var cardObject = PFObject(className: "YourCard")
cardObject["cardNumber"] = cardNumber
cardObject["balance"] = balance
cardObject["expire"] = date
cardObject["validFlg"] = cardStatus
cardObject.saveInBackgroundWithBlock {
(success: Bool!, error: NSError!) -> Void in
if (success != nil) {
NSLog("Object created with id: \(cardObject.objectId)")
} else {
NSLog("%#", error)
}
}
dbId = cardObject.objectId
I couldn't get objectId, how can I get it?
Thank you very much in advance.
As the name of your function already says, it is a function which is called asynchron. That means that the main thread doesn't wait for the function to finish. So you will get an (still) empty objectId.
To get your objectID after saveInBackground is finished, you have to put your line where you get the ID into the if-clause.
var cardObject = PFObject(className: "YourCard")
cardObject["cardNumber"] = cardNumber
cardObject["balance"] = balance
cardObject["expire"] = date
cardObject["validFlg"] = cardStatus
cardObject.saveInBackgroundWithBlock {
(success: Bool!, error: NSError!) -> Void in
if (success != nil) {
NSLog("Object created with id: \(cardObject.objectId)")
//Gets called if save was done properly
dbId = cardObject.objectId
} else {
NSLog("%#", error)
}
}
Another option would be to call save() in the main thread. That way the function finishes before you call the objectId. Parse doesn't recommend that, but it's a possibility:
cardObject.save()
dbId = cardObject.objectId