How to get objectId immediately after save data with Parse and swift - swift

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

Related

Code not executing in docRef.getDocument?

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.

How to use the when function in Promisekit loop

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)
}
}

Using Do/Catch in Swift

I am working on an app and want to get data back from a function. However sometimes data is missing or is different from the kind of that I want to retrieve. I am new to Swift and I can't find a way to write a function that does a little bit of processing and returns this data. When this data is missing, the function should give back a string "Not Found". Like this:
func processData(data:String) {
do {
//processing
var result = processedData
} catch {
var result = "Not Found"
}
return result
}
It would be very nice if somebody could help me.
You should check if the result is nil.
func processData(data: String?) -> String {
guard let result = data else {
return "Not Found"
  }
return result
}
The most concise way of doing it would be using the guard-let construct:
func processData(data: String?) -> String {
// Assuming getProcessedData(:) returns your processed data
guard let result = getProcessedData(data) else {
return "Not found"
}
return result
}
Also, your function is missing a return type. You must specify the return type like -> TYPE in all functions that return some value.
Those answer were written till mine are right. There is one way: with handler check get result and use by your point.
enum Errors: Error {
case noData
case unknownError
}
func progress(data: String?, completionHandler: #escaping (_ result: String? , _ error: Error?) -> Void ) {
guard let data = data else {
// Data is missing
throw nil, Errors.noData
}
// Do other things, and throw if necessary
result = data
return result, nil
}
// example of calling this function
process(data: "A data to process"){(result, error) -> Void in
//do any stuff
/*if error == nil {
}*/
}
A good practice in swift would be to use correctly the throws errors
This is an example inspired from yours :
enum Errors: Error {
case noData
case unknownError
}
func progress(data: String?) throws -> String {
guard let data = data else {
// Data is missing
throw Errors.noData
}
// Do other things, and throw if necessary
result = data
return result
}
do {
try process(data: "A data to process")
} catch {
print("An error occurred: \(error)")
}
You can try this code as is in a Swift Playgound
Your function needs to be explicit about returning something with e.g. -> String Also do-catch is for methods that can throw an error. It seems like you need to take a look at how to use optionals. Optionals can have a value or they can have no value.
fun processData(data: String) -> String {
var result: String?
// Do some processing and assign the result to result variable
guard let result = result else { return "Not Found" }
return result
}

checking undefined value or specific value before retrieving from parse

checking undefined value before retrieving from parse
I am making a simple app, and implementing the userInformation part. The user can edit his info, but I have trouble that if user doesn't put any info, it will crash when I try to retrieve data from an undefined column.
This is my code to retrieve the user data. If there is data to parse it won't crash, otherwise it will.
var query = PFQuery(className: "Note")
query.getObjectInBackgroundWithId("kg8KhAWCms", block: {
(obj, error)in
if let score = obj! as? PFObject {
print(score.objectForKey("title"))
var nickname = (score.objectForKey("title")) as! String
self.nickNameLabel.text = nickname
} else {
print(error)
}
})
I tried this code as well, but it has error which is binary operator '!=' cannot be applied to operands of type 'String' and 'NiLiteralConvertible'
var query = PFQuery(className: "Note")
query.getObjectInBackgroundWithId("kg8KhAWCms", block: {
(obj, error)in
if let obj = obj! as? PFObject {
print(obj.objectForKey("title"))
var nickname = (obj.objectForKey("title")) as! String
if (nickname != nil) {
self.nickNameLabel.text = nickname
}else{
self.nickNameLabel.text = "you don't have a nick name"
}
} else {
print(error)
}
})
So I am asking how can I handle retrieving undefined value before crash? (please write full code for me)
Is there a way I can check undefined value or specific value in column before I retrieve it?
///like this
if (value in parse == "ABC") {
print("yes")
}

Retrieving parse.com data in Swift

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
})