/* Checks Is Username Already Exists
Take - username
Return - Bool (True/False) */
func checkIsUserExists(username: String, completion: ((isUser: Bool?) -> Void)!) {
var isPresent: Bool = false;
let query: PFQuery = PFQuery(className: "your_class_name")
query.whereKey("your_key", equalTo:username)
query.findObjectsInBackgroundWithBlock {
(objects: [AnyObject]?, error: NSError?) -> Void in
if error == nil {
if (objects!.count > 0) {
isPresent = true;
}
} else {
// Log details of the failure
println("Error: \(error) \(error!.userInfo!)")
}
completion(isUser: isPresent);
}
}
I found this function method that checks if the user exists in parse database but I dont get it what is the proper way to call it?
checkIsUserExists("user#gm.com, comletion.. ?)
It requires a closure that acts as a callback. So you'd call it in the following way:
checkIsUserExists("User Name"){isUser in if let user = isUser where user {
userFound()
}
else {
userNotFound()
}
}
Assuming you also had the following methods in place:
func userFound() {
// do something if the user was found
}
func userNotFound() {
// do something if the user was not found
}
The important keyword is in. Before the keyword, within the curly braces, I've named the value that is being captured isUser. It is a Bool as we can see from the method. And the closure is not required to return anything: (isUser: Bool?) -> Void)! hence the word Void. After the in keyword we can use the captured value to do whatever we wish with the optional true or false value. Here I call one of two functions.
In terms of code it is a very poor callback because while we know whether the user exists by the time the callback happens there might be several callbacks waiting in line and so we won't know which user exists because the user name is not passed to the closure.
You can find out plenty about closures in the Swift documentation.
got it!
The correct way is
checkIsUserExists(userEmail.text!)
{
(isUser: Bool?) in
print(isUser)
}
WOW! what a weird function call
Related
I have a function set up to return a Promise<PFObject>. I would like to use this function in PromiseKit's when(fulfilled:) functionality, but whenever I try to do so, I get an error. Here is the function which returns the Promise<PFObject>:
func Query() -> Promise<PFObject>{
return Promise{ fulfill, reject in
let linkQueryy = PFUser.query()
linkQueryy?.findObjectsInBackground(block: { (objectss, error) in
if let objects = objectss{
for object in objects{
fulfill(object)
}
}
})
}
}
As you can see, the function returns the Promise upon fulfillment. Thus, I tried to set up a when statement in my viewDidLoad() as follows:
override func viewDidLoad() {
super.viewDidLoad()
when(fulfilled: Query()).then{
//do more asynch stuff
}
}
However, I get the error that xcode cannot "invoke 'when' with an argument list type of '(fulfilled: Promise<PFObject>)'". I do not know how to fix this as I thought I had it set up correctly. The when needs a promise, and I am giving it one so I am not sure what to do.
Try as follows :
when(fulfilled: [linkQueryy()] as! [Promise<Any>]).then { _ in
// do more asynch stuff
}
The parameter fulfilled: needs to be an iterable.
By the way, when(fulfilled:) is necessary only when you have many promises and need wait for all to complete successfully. But in your code, you need to wait for only one promise.
For a single promise, the better way is to form a chain as follows :
firstly {
linkQueryy()
}.then { _ -> Void in
// do more asynch stuff
}.catch { _ in
// error!
}
I am programming an app which utilizes a parse-server (hosted by heroku) database. I have several functions which pull information from the DB, but they are all inherently asynchronous (because of the way parse's .findObjectinBackground works.) The issue with this as that the later DB queries require information from previous queries. Since the information being pulled is asynchronous, I decided to implement PromiseKit to ensure that the object has been found from findObjectinBackground from the first query, before running the second query.
The general form of the queries is as follows:
let query = PFQuery(classname: "Hello")
query?.findObjectsInBackground(block: { (objects, error) in
if let objectss = objects{
for object in objectss{ //object needs to be pulled
arrayOfInterest.append(object)
//array must be appended before moving on to next query
}
}
})
I just do not know how exactly to do this. This is the way I would like to implement it:
import PromiseKit
override func viewDidLoad(){
when(/*query object is retrieved/array is appended*/).then{
//perform the next query
}
}
I simply don't know exactly what to put in the when() and the .then{}. I tried making the queries into their own individual functions and calling them inside those two (when and then) functions, but I basically get told that I cannot because they return void. Also, I cannot simply ensure the first query is run in the when() as the query.findObjectinBackground(in the query) being asynchronous is the issue. The object specifically needs to be pulled, not just the query run, before the next one can fire.
Do you want create your promise?
You need write a function that return a Promise<Any>. In your case, need to encapsulate the entire code inside of Promise { fulfill, reject in HERE}. For example:
func foo(className: String) -> Promise<[TypeOfArrayOfInterest]> {
return Promise { fulfill, reject in
let query = PFQuery(classname: className)
query?.findObjectsInBackground(block: { (objects, error) in
if let error = error {
reject(error) // call reject when some error happened
return
}
if let objectss = objects {
for object in objectss{
arrayOfInterest.append(object)
}
fulfill(arrayOfInterest) // call fulfill with some value
}
})
}
}
Then, you call this function in firstly:
firstly {
foo(className: "Hello")
}.then { myArrayOfInterest -> Void in
// do thing with myArrayOfInterest
}.catch { error in
// some error happened, and the reject was called!
}
Also, I wrote a post in my blog about, among other things, PromiseKit and architecture. It may be helpful: http://macalogs.com.br/ios/rails/ifce/2017/01/01/experiencias-eventbee.html
Edit
More complete example:
func foo() -> Promise<Int> {
...
}
func bar(someText: String) -> Promise<String> {
...
}
func baz() -> Promise<Void> {
...
}
func runPromises() {
firstly {
foo()
}.then { value -> Promise<Any> in
if value == 0 {
return bar(someText: "no")
} else {
return bar(someText: "yes")
}
}.then { _ /* I don't want a String! */ -> Promise<Void> in
baz()
}.catch { error in
// some error happened, and the reject was called!
}
}
Or if you don't want a catch:
_ = firstly {
foo()
}.then { _ in
// do some thing
}
Swift have a greate type inference, but, when use PromiseKit, I recommend always write a type in then closure, to avoid erros.
I want to make a function that fetches a record from CloudKit, if it encounters a temporary network error the function should retry.
func fetchRecord(withRecordID recordID: CKRecordID, returnBlock: (optError: ErrorType?) -> Void){
func internalReturnBlock(optError optError: ErrorType?){
if NSThread.isMainThread() {
returnBlock(optError: optError)
}
else{
dispatch_async(dispatch_get_main_queue(), {
returnBlock(optError: optError)
})
}
}
func internalWork(){
privateDB.fetchRecordWithID(recordID) { (optRecord, optError) in
if let error = optError{
// IF NETWORK ERROR RETRY
internalWork()
}
else{
internalReturnBlock(optError: nil)
}
}
}
internalWork()
}
Here I define such function (simplified), If the fetch encounters an error it retries by calling the nested function internalWork()
My question is what would be the difference between using nested functions or creating local closure variables?
For example, here I change the internalReturnBlock to a closure variable:
func fetchRecord2(withRecordID recordID: CKRecordID, returnBlock: (optError: ErrorType?) -> Void){
var internalReturnBlock = { (optError: NSError?) in
if NSThread.isMainThread() {
returnBlock(optError: optError)
}
else{
dispatch_async(dispatch_get_main_queue(), {
returnBlock(optError: optError)
})
}
}
func internalWork(){
privateDB.fetchRecordWithID(recordID) { (optRecord, optError) in
if let error = optError{
// IF NETWORK ERROR RETRY
internalWork()
}
else{
internalReturnBlock(nil)
}
}
}
internalWork()
}
What are the differences between using a nested function vs a variable block?
Any advantages or problems?
There is no difference in effect. One is a declared function with a name, the other is anonymous. But they are both functions. And a function is a closure in Swift, so they are both closures.
An anonymous function is permitted to use some abbreviations of form, such as the omission of return in a one-liner that returns a value. But none of those abbreviations makes any ultimate effective difference.
However, an anonymous function in Swift has one feature a declared function does not — a capture list. This can help avoid retain cycles.
f {
[unowned self] in
return self.name
}
Also, an anonymous function is defined after the declaration of the function that takes it as a parameter, so it can use terms that appear in that declaration:
f(param:String) {
return param
}
But if you are not using those features, then it doesn't matter which you use. They work identically.
I first tried this solution to return a bool in the spot I want to return it. However, due to the parse.com function saveInBackgroundWithBlock() being a void return function, I got the error "Unexpected non-void return value in void function".
func saveObjectToParse(gameLocal: Game) -> Bool {
let game = PFObject(className:"Game")
game["sport"] = gameLocal.sport.rawValue
var saved = false
game.saveInBackgroundWithBlock {
(success: Bool, error: NSError?) -> Void in
if (success) {
print("Object has been saved.")
saved = true
return saved
} else {
print("parse error")
return saved
}
}
}
So, I tried moving the return statements out of the subfunction like this:
func saveObjectToParse(gameLocal: Game) -> Bool {
let game = PFObject(className:"Game")
game["sport"] = gameLocal.sport.rawValue
var saved = false
game.saveInBackgroundWithBlock {
(success: Bool, error: NSError?) -> Void in
if (success) {
print("Object has been saved.")
saved = true
} else {
print("parse error")
}
}
return saved
}
However, this returns saved before the saveInBackgroundWithBlock() block executes because it is a background process. Therefore, saved will never be true, even when it is intended to be. I have tried adding a boolean flag called done and tried waiting with a while(!done) loop, but this freezes the program on the loop and the background process never executes. How can I fix these problems?
I agree with restructuring not needing a bool returned, but if you really, really need this set up, you could save your object synchronously (so your code will wait) like so,
do {
try game.save()
} catch {
print(error)
}
Returning a value from a function but from another function doesn't make architectural sense. Nor is it possible.
You either will need to change your implementation and make both methods independent or think of using a semaphore.
http://www.g8production.com/post/76942348764/wait-for-blocks-execution-using-a-dispatch
What you are trying to do (create a helper function to wrap the Parse save function) makes perfect sense and can be easily accomplished.
You do not need to use semaphores and you certainly don't want to perform the operation synchronously. Instead, use a completion hander to let you know when the save has completed. For more information on completion handlers see this link
func saveObjectToParse(gameLocal: Game, completion: (gameSaved: Bool) -> Void) {
let game = PFObject(className:"Game")
game["sport"] = gameLocal.sport.rawValue
game.saveInBackgroundWithBlock {
(success: Bool, error: NSError?) -> Void in
// Set the completion handler to be result of the Parse save operation
completion(gameSaved: success)
}
}
You may then call this function like so
saveObjectToParse(someGameObject) { (gameSaved: Bool) in
if gameSaved {
print("The game has been saved.")
} else {
print("Error while saving the game")
}
}
Using this technique, you could similarly propagate the entire callback of saveInBackgroundWithBlock through your function so you could inspect errors when they occur.
Edit: It looks like you may also be using your own custom class to represent the Game object. I would recommend looking into subclassing PFObject so you can easily and directly model your Parse classes. More details in the documentation
I want to create a function to check if user_id is already in my database.
class func checkIfUserExsits(uid:String) -> Bool {
userRef.childByAppendingPath(uid).observeSingleEventOfType(.Value, withBlock: { (snapShot: FDataSnapshot!) -> Void in
if snapShot.value is NSNull {
return false
} else {
return true
}
})
}
However, observeSingleEventOfType is a API provided by 3rd party Firebase. It is defined to return Void.
(void)observeSingleEventOfType:(FEventType)eventType withBlock:(void ( ^ ) ( FDataSnapshot *snapshot ))block
Error: Type 'Void' does not conform to protocol 'BooleanLiteralConvertible'
Appreciate any kind of helps.
UPDATE
I am trying a different way:
class func checkIfExist(uid: String) -> Bool {
var answer:Bool = false
var text:String = "not yet completed"
let queue = dispatch_group_create()
dispatch_group_enter(queue)
userRef.childByAppendingPath(uid).observeSingleEventOfType(.Value, withBlock: { (snapShot: FDataSnapshot!) -> Void in
if snapShot.value is NSNull {
text = "This is a new user"
answer = false
dispatch_group_leave(queue)
} else {
text = "Found the user in Firebase"
answer = true
dispatch_group_leave(queue)
}
})
dispatch_group_wait(queue, DISPATCH_TIME_FOREVER)
println(text)
return answer
}
Somehow it just freeze there. I know this approach could be off-topic now. But please help.
You should employ asynchronous (ie, escaping) completion handler yourself:
class func checkIfUserExists(uid: String, completion: #escaping (Bool) -> Void) {
userRef.childByAppendingPath(uid).observeSingleEventOfType(.Value) { snapShot in
if snapShot.value is NSNull {
completion(false)
} else {
completion(true)
}
}
}
You can then call this like so:
MyClass.checkIfUserExists(uid) { success in
// use success here
}
// but not here
In your revised question, you demonstrate the use of dispatch groups to make this asynchronous method behave synchronously. (Semaphores are also often used to the same ends.)
Two issues:
This will deadlock if they dispatch their completion handler back to the main queue (and in many cases, libraries will do this to simplify life for us), because you're coincidentally blocking the very same thread they're trying to use. I don't know if that's what they've done here, but is likely.
If you want to confirm this, temporarily remove dispatch group and then examine NSThread.isMainThread and see if it's running in main thread or not.
You never should block the main thread, anyway. They provided an asynchronous interface for good reason, so you should use asynchronous patterns when calling it. Don't fight the asynchronous patterns, but rather embrace them.