How to make a CompletionHandler with Firebase Swift 3 - xcode

I need to get some informations from Firebase to out it on UIViewCell. But the problem is that the function return before he get all the value. I know that's because it's asynchronous, i tried to make a completion Handler like that:
static func hardProcessingWithString(input: String, completion: #escaping (_ result: String) -> Void) {
Database.database().reference().child("Player_1").observe(.value) {
(firDataSnapshot) in
completion((firDataSnapshot.value as? String)!)
}
}
This is how i try to get the value :
var myVar: String!
hardProcessingWithString(input: "commands"){
(result: String) in
myVar = result
}
I get this error when I call the function:
Could not cast value of type '__NSDictionaryM' (0x102e292b0) to 'NSString' (0x102434c60).
Here's my Firebase database:
Or if you know how to make a Promise with Firebase let me know!

Step 1:
Create a swift file like Constant.swift. Then place the below code inside it
typealias DownloadComplete = () -> ()
Step 2:
Create a function where you want.
func hardProcessingWithString(completed: #escaping DownloadComplete) {
Database.database().reference().child("Player_1").observe (.value, with: { (firDataSnapshot) in
// put your code here
completed()
})
}
Step 3:
when you call above method in your code
hardProcessingWithString() {
// you can get the result here
}

Related

getting information outside of .observe method in swift Firebase

So i was able to retrieve all data from my firebase database using the following function. I was wondering if there is a way i can save the output which is "print(name)" in the self.GetUsername into a global variable
func GetUsername(uid:String , completion: #escaping ([Int]) -> ()) {
Database.database().reference().child("Songs").observeSingleEvent(of: .value) { (snapshot:DataSnapshot) in
var array: [Int] = []
for item in snapshot.children.allObjects as! [DataSnapshot]
{
array.append(item.value as! Int)
}
completion(array)
}
}
self.GetUsername(uid: (Auth.auth().currentUser?.uid)!) { (name) in
print(name)
}

Cannot invoke with an argument list of type Swift 3

Error happens here
self.iotDataManager.register(withShadow: statusThingName, eventCallback: self.deviceShadowCallback)
where
let statusThingName="TemperatureStatus"
and
func deviceShadowCallback(_ name:String!, operation:AWSIoTShadowOperationType, operationStatus:AWSIoTShadowOperationStatusType, clientToken:String!, payload:Data!) -> Void {
DispatchQueue.main.async {
//code
}
}
And signature is
self.iotDataManager.register(withShadow: <String!>, eventCallback: { (<String?>, <AWSIoTShadowOperationType>, <AWSIoTShadowOperationStatusType>, <String?>, <Data?>) in
<code>
})
I think this could be a bug in Swift , this is conversion from Swift 2 to 3 that I am trying to fix.
Declaration of the functions:
func deviceShadowCallback(
_ name: String?,
operation: AWSIoTShadowOperationType,
operationStatus: AWSIoTShadowOperationStatusType,
clientToken: String?,
payload: Data? ) {
}
func register(
withShadow: String,
eventCallback: (
String?,
AWSIoTShadowOperationType,
AWSIoTShadowOperationStatusType,
String?,
Data? ) -> Void) {
}
Execution:
let statusThingName = "status"
register(withShadow: statusThingName, eventCallback: deviceShadowCallback)
I could compile and run it without any problems.

logInWithReadPermissions(_:handler:)' is deprecated: use logInWithReadPermissions:fromViewController:handler: instead

Using the latest XCode, I'm getting this error:
'logInWithReadPermissions(_:handler:)' is deprecated:
use logInWithReadPermissions:fromViewController:handler: instead'
How would I alternatively re-format my code? here is the whole function that it is in:
#IBAction func fbBtnPressed(sender: UIButton!) {
let facebookLogin = FBSDKLoginManager()
facebookLogin.logInWithReadPermissions(["email"]) {
(facebookResult: FBSDKLoginManagerLoginResult!,facebookError: NSError!) in
print("Facebook login failed. Error \(facebookError)")
}
}
Xcode 8.2 beta (8C30a) :
fbLoginManager.logIn(withReadPermissions:["email"], from: self, handler: {
(result, error) -> Void in
if (error == nil){
let fbloginresult : FBSDKLoginManagerLoginResult? = result
if(fbloginresult?.isCancelled)! {
//Show Cancel alert
} else if(fbloginresult?.grantedPermissions.contains("email"))! {
//self.returnUserData()
//fbLoginManager.logOut()
}
}
})
Figured it out guys! If anyone is lurking on this post, here is the new code:
#IBAction func fbBtnPressed(sender: UIButton!) {
let facebookLogin = FBSDKLoginManager()
facebookLogin.logInWithReadPermissions(["email"], fromViewController: self) { (facebookResult: FBSDKLoginManagerLoginResult!, facebookError: NSError!) -> Void in
print("Facebook login failed. Error \(facebookError)")
}
}
If your fbBtnPressed function is in a view controlle class, just pass self to the fromViewController parameter.
facebookLogin.logInWithReadPermissions(["email"], fromViewController: self) { ... }
A note though, it's encouraged in Swift and Obj-C that your function names prioritize readability over being compact. For example, I would name your button handler facebookLoginButtonPressed. It's longer but much more readable.

Swift - closure expression syntax

i'm working with Alamofire library, i've noticed that they use this syntax
func download(method: Alamofire.Method, URLString: URLStringConvertible, headers: [String : String]? = default, #destination: Alamofire.Request.DownloadFileDestination) -> Alamofire.Request
that takes 4 parameters as input but if you go to the documentation to call the method they use the following
Alamofire.download(.GET, "http://httpbin.org/stream/100") { temporaryURL, response in
let fileManager = NSFileManager.defaultManager()
if let directoryURL = fileManager.URLsForDirectory(.DocumentDirectory, inDomains: .UserDomainMask)[0] as? NSURL {
let pathComponent = response.suggestedFilename
return directoryURL.URLByAppendingPathComponent(pathComponent!)
}
return temporaryURL}
that takes only 2 parameters (method: and URLString:) i think that the param headers is optional because provide the default statement.
I don't understand how Destination is handled.
Could you please explain me how the closure is handled?
Why the curl braces is open AFTER the method call and not inside the call after the URLString param?
I really appreciate any help you can provide
Marco
It's the trailing closure technique
If a method accepts a closure as last param
class Foo {
func doSomething(number: Int, word: String, completion: () -> ()) {
}
}
You can call it following the classic way:
Foo().doSomething(1, word: "hello", completion: { () -> () in
// your code here
})
Or using the trailing closure technique:
Foo().doSomething(1, word: "hello") { () -> () in
// your code here
}
The result is the same, it just a more elegant (IMHO) syntax.

Swift URL Response is nil

I have created a custom DataManager class. Inside it I want to fetch data in a method and return an NSData object to convert to JSON afterwards.
I have tried to get the data using the completionHandler but no luck:
class func fetchData() -> NSData? {
var session = NSURLSession.sharedSession(),
result = NSData?()
let DataURL : NSURL = NSURL(string: "http://...file.json")!
let sessionTask = session.dataTaskWithURL(DataURL, completionHandler: { (data: NSData!, response: NSURLResponse!, error: NSError!) -> Void in
result = data
})
sessionTask.resume()
return result
}
The dataTask runs asynchronously. That means that the completion handler closure will not be called by the time you return from fetchData. Thus, result will not have been set yet.
Because of this, you should not try to retrieve data synchronously from an asynchronous method. Instead, you should employ an asynchronous completion handler pattern yourself:
class func fetchData(completion: #escaping (Data?, Error?) -> Void) {
let session = URLSession.shared
let url = URL(string: "http://...file.json")!
let task = session.dataTask(with: url) { data, response, error in
completion(data, error)
}
task.resume()
}
And you'd call it like so:
MyClass.fetchData { data, error in
guard let data = data, error == nil else {
print(error ?? "Unknown error")
return
}
// use `data` here; remember to dispatch UI and model updates to the main queue
}
// but do not try to use `data` here
...
FYI, for the original pre-Swift 3 syntax, see previous revision of this answer.

Resources