I'm using the ParseFacebookUtilsV4 and the fb idk seem to be having issues with retrieving the users info just to print into the console for now. The issue is that it seems that the block to start the request isn't being executed since whenever i debug it just seems to skip the start completion handler.
// View controller code
PFFacebookUtils.facebookLoginManager().loginBehavior = .web
var loginTask = PFFacebookUtils.logInInBackground(withReadPermissions: [])
loginTask.continue( { (bfTask) -> Any? in
print("I'm here")
let request = FBSDKGraphRequest(graphPath:"me", parameters: ["fields":"id,email,name,first_name,last_name,picture"] )
print(request)
request?.start {
(connection, result, error) in
print(result)
}
return ""
})
// App delegate config
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
let configuration = ParseClientConfiguration {
$0.applicationId = "xxxx"
$0.clientKey = "xxxxx"
$0.server = "https://parseapi.back4app.com"
}
Parse.initialize(with: configuration)
PFFacebookUtils.initializeFacebook(applicationLaunchOptions: launchOptions)
PFTwitterUtils.initialize(withConsumerKey: "xxxxx", consumerSecret: "xxxxx")
// Override point for customization after application launch.
return true
}
here's the func I use for the Facebook request. I am using a block request:
func loadFacebookUserDetails() {
// Define fields we would like to read from Facebook User object
let requestParameters = ["fields": "id, email, first_name, last_name, name"]
// Send Facebook Graph API Request for /me
let userDetails = FBSDKGraphRequest(graphPath: "me", parameters: requestParameters)
userDetails.startWithCompletionHandler({
(connection, result, error: NSError!) -> Void in
if error != nil {
let userMessage = error!.localizedDescription
let myAlert = UIAlertController(title: "Alert", message: userMessage, preferredStyle: UIAlertControllerStyle.Alert)
let okAction = UIAlertAction(title: "Ok", style: UIAlertActionStyle.Default, handler: nil)
myAlert.addAction(okAction)
self.presentViewController(myAlert, animated: true, completion: nil)
PFUser.logOut()
return
}
// Extract user fields
let userId:String = result.objectForKey("id") as! String
let userEmail:String? = result.objectForKey("email") as? String
let userFirstName:String? = result.objectForKey("first_name") as? String
let userLastName:String? = result.objectForKey("last_name") as? String
// Get Facebook profile picture
let userProfile = "https://graph.facebook.com/" + userId + "/picture?type=large"
let profilePictureUrl = NSURL(string: userProfile)
let profilePictureData = NSData(contentsOfURL: profilePictureUrl!)
// Prepare PFUser object
if(profilePictureData != nil)
{
let profileFileObject = PFFile(name:"profilePic.jpeg",data:profilePictureData!)
PFUser.currentUser()?.setObject(profileFileObject!, forKey: "ProfilePic")
}
PFUser.currentUser()?.setObject(userFirstName!, forKey: "Name")
PFUser.currentUser()?.setObject(userLastName!, forKey: "last_name")
if let userEmail = userEmail
{
PFUser.currentUser()?.email = userEmail
PFUser.currentUser()?.username = userEmail
}
PFUser.currentUser()?.saveInBackgroundWithBlock({ (success, error) -> Void in
if(error != nil)
{
let userMessage = error!.localizedDescription
let myAlert = UIAlertController(title: "Alert", message: userMessage, preferredStyle: UIAlertControllerStyle.Alert)
let okAction = UIAlertAction(title: "Ok", style: UIAlertActionStyle.Default, handler: nil)
myAlert.addAction(okAction)
self.presentViewController(myAlert, animated: true, completion: nil)
PFUser.logOut()
return
}
if(success)
{
if !userId.isEmpty
{
NSUserDefaults.standardUserDefaults().setObject(userId, forKey: "user_name")
NSUserDefaults.standardUserDefaults().synchronize()
dispatch_async(dispatch_get_main_queue()) {
self.dismissViewControllerAnimated(true, completion: nil)
}
}
}
})
})
}
Related
The problem that I'm facing is that I have successfully created the array and have displayed the values like so:
Users
-uid
- Name: Example
- Profile Pic URL: example12345
- email: example#example.co.uk
However, in another swift file I have successfully generated a personality type and am struggling to add this to the array so that I end up with something that looks like this:
Users
-uid
- Name: Example
- Profile Pic URL:
- email: example#example.co.uk
- personality type: INTJ
I have tried copying the code from the previous swift class to no avail
This is the code for the working firebase array
#IBAction func createAccountAction(_ sender: AnyObject) {
let usersRef = Database.database().reference().child("Users")
let userDictionary : NSDictionary = ["email" : emailTextField.text!, "Name": nameTextField.text!]
if emailTextField.text == "" {
let alertController = UIAlertController(title: "Error", message: "Please enter your email and password", preferredStyle: .alert)
let defaultAction = UIAlertAction(title: "OK", style: .cancel, handler: nil)
alertController.addAction(defaultAction)
self.present(alertController, animated: true, completion: nil)
} else {
Auth.auth().createUser(withEmail: self.emailTextField.text ?? "", password: self.passwordTextField.text ?? "") { (result, error) in
if error != nil {
let alertController = UIAlertController(title: "Error", message: error?.localizedDescription, preferredStyle: .alert)
let defaultAction = UIAlertAction(title: "OK", style: .cancel, handler: nil)
alertController.addAction(defaultAction)
self.present(alertController, animated: true, completion: nil)
return
}
guard let user = result?.user else { return }
let vc = self.storyboard?.instantiateViewController(withIdentifier: "ViewController") as! ViewController
self.present(vc, animated: true, completion: nil)
// HERE YOU SET THE VALUES
usersRef.child(user.uid).setValue(userDictionary, withCompletionBlock: { (error, ref) in
if error != nil { print(error); return }
let imageName = NSUUID().uuidString
let storageRef = Storage.storage().reference().child("profile_images").child("\(imageName).png")
if let profileImageUrl = self.profilePicture.image, let uploadData = UIImageJPEGRepresentation(self.profilePicture.image!, 0.1) {
storageRef.putData(uploadData, metadata: nil, completion: { (metadata, error) in
if error != nil, metadata != nil {
print(error ?? "")
return
}
storageRef.downloadURL(completion: { (url, error) in
if error != nil {
print(error!.localizedDescription)
return
}
if let profileImageUrl = url?.absoluteString {
self.addImageURLToDatabase(uid: user.uid, values: ["profile photo URL": profileImageUrl as AnyObject])
}
})
})
}
}
)}
}
}
This is the other swift file function which generates the personality type which I would like to add to the array
#IBAction func JPbtn(_ sender: Any) {
if (Judging < Perceiving){
Result3 = "P"
} else {
Result3 = "J"
}
let PersonalityType = "\(Result) \(Result1) \(Result2) \(Result3)"
print(PersonalityType)
let vc = self.storyboard?.instantiateViewController(withIdentifier: "Example") as! ViewController
self.present(vc, animated: true, completion: nil)
}
So if you are just trying to add a new key with a value, all you need to do is create a new reference like this.
guard let currentUserUID = Auth.auth().currentUser?.uid else { return }
print(currentUserUID)
let userPersonalityRef = Database.database().reference().child("users").child(currentUserUID).child("personality")
userPersonalityRef.setValue("Some Value")
When you set the value it can also be a dictionary if you want. But if your users don't all have personality make sure it optional on your data model or else It might crash your app. When you are getting your user from firebase.
I want to store the ngoid value in userDefaults so that I can access it in my next API call in the next viewController class. How do I do it?
Here is the code I have written:
#IBAction func loginbutton(_ sender: Any) {
let myUrl = NSURL(string: "http://www.shreetechnosolution.com/funded/ngo_login.php")
let request = NSMutableURLRequest(url:myUrl! as URL)
request.httpMethod = "POST"// Compose a query string
let postString = "uname=\(textfieldusername.text!)&password=\(textfieldpassword.text!)";
request.httpBody = postString.data(using: String.Encoding.utf8)
let task = URLSession.shared.dataTask(with: request as URLRequest){ data , response , error in
if error != nil
{
//let alert = UIAlertView()
let alert = UIAlertController(title: "Alert Box !", message: "Login Failed", preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "OK", style: .default, handler: nil))
return
}
// You can print out response object
print("*****response = \(String(describing: response))")
let responseString = NSString(data: data! , encoding: String.Encoding.utf8.rawValue )
if ((responseString?.contains("")) == nil) {
print("incorrect - try again")
let alert = UIAlertController(title: "Try Again", message: "Username or Password Incorrect", preferredStyle: .alert)
let yesAction = UIAlertAction(title: "Nochmalversuchen", style: .default) { (action) -> Void in
}
// Add Actions
alert.addAction(yesAction)
// Present Alert Controller
self.present(alert, animated: true, completion: nil)
}
else {
print("correct good")
}
print("*****response data = \(responseString!)")
do {
//create json object from data
if let json = try JSONSerialization.jsonObject(with: data!, options: .mutableContainers) as? NSDictionary {
if let email = json["UserName"] as? String,
let password1 = json["passowrd"] as? String {
print ("Found User id: called \(email)")
}
let msg = (json.value(forKey: "message") as! NSString!) as String
//let id = json.value(forKey: "NgoId") as! Int!
let ngoid = json.value(forKey: "NgoId") as? String
print(ngoid ?? "")
let defaults = UserDefaults.standard
defaults.set(ngoid, forKey: "ngoid")
print(ngoid!)
DispatchQueue.main.async {
self.alert = UIAlertController(title: "Alert Box!", message: "\(msg)", preferredStyle: .alert)
self.action = UIAlertAction(title: "OK", style: .default) { (action) -> Void in
let vtabbar1 = self.storyboard?.instantiateViewController(withIdentifier: "tabbar1")
self.navigationController?.pushViewController(vtabbar1!, animated: true)
}
self.alert.addAction(self.action)
self.present(self.alert, animated: true, completion: nil)
}
}
}
catch let error {
print(error)
}
}
task.resume()
}
You could use UserDefaults but if you only need to use the value on the next viewController you should use a segue for this purpose. Here is a guide of how that works. Otherwise use UserDefaults like the example below:
// To set the value
UserDefaults.standard.set(ngoid, forKey: "NgoId")
// To get the value
let id = UserDefaults.standard.string(forKey: "NgoId")
This is not a best way to save in user default and then use in next ViewController, use this overdid method
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "ShowCounterSegue"
{
if let destinationVC = segue.destinationViewController as? OtherViewController {
destinationVC.ngoid = ngoid
}
}
}
use ngoid anywhere in your next ViewController api call.
I'm working on login form. I'm a fresher on iOS development.
After successful login, I want to show an alert after completion of json parsing. I've parsed Ngoid inside a do while block. Now I want to pass the value "Ngoid" to the next view controller so that it can be used to fetch the further data.
Main Problem: Here is the code I have written and it gives me error to write alert it on main thread only.
As I want the "Ngoid" value for further use there, so how should I write it and what is the correct way to execute the code?
Here is the code I have written:
#IBAction func loginbutton(_ sender: Any) {
let myUrl = NSURL(string: "http://www.shreetechnosolution.com/funded/ngo_login.php")
let request = NSMutableURLRequest(url:myUrl! as URL)
request.httpMethod = "POST"// Compose a query string
let postString = "uname=\(textfieldusername.text!)&password=\(textfieldpassword.text!)";
request.httpBody = postString.data(using: String.Encoding.utf8)
let task = URLSession.shared.dataTask(with: request as URLRequest){ data , response , error in
if error != nil
{
//let alert = UIAlertView()
let alert = UIAlertController(title: "Alert Box !", message: "Login Failed", preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "OK", style: .default, handler: nil))
return
}
// You can print out response object
print("*****response = \(String(describing: response))")
let responseString = NSString(data: data! , encoding: String.Encoding.utf8.rawValue )
if ((responseString?.contains("")) == nil) {
print("incorrect - try again")
let alert = UIAlertController(title: "Try Again", message: "Username or Password Incorrect", preferredStyle: .alert)
let yesAction = UIAlertAction(title: "Nochmalversuchen", style: .default) { (action) -> Void in
}
// Add Actions
alert.addAction(yesAction)
// Present Alert Controller
self.present(alert, animated: true, completion: nil)
}
else {
print("correct good")
}
print("*****response data = \(responseString!)")
do {
//create json object from data
if let json = try JSONSerialization.jsonObject(with: data!, options: .mutableContainers) as? NSDictionary {
if let email = json["UserName"] as? String,
let password1 = json["passowrd"] as? String {
print ("Found User id: called \(email)")
}
let msg = (json.value(forKey: "message") as! NSString!) as String
let id = (json.value(forKey: "NgoId") as! NSString!) as String
// let alert : UIAlertView = UIAlertView(title: "Alert box!", message: "\(msg!).",delegate: nil, cancelButtonTitle: "OK")
// alert.show()
self.alert = UIAlertController(title: "Alert Box!", message: "\(msg)", preferredStyle: .alert)
print("the alert\(self.alert)")
self.action = UIAlertAction(title: "OK", style: .default) { (action) -> Void in
let viewControllerYouWantToPresent = self.storyboard?.instantiateViewController(withIdentifier: "pass1") as! ViewControllerngodetails
viewControllerYouWantToPresent.temp1 = self.id
self.present(viewControllerYouWantToPresent, animated: true, completion: nil)
}
self.alert.addAction(self.action)
self.present(self.alert, animated: true, completion: nil)
}
}catch let error {
print(error)
}
}
task.resume()
}
A pro tip:
All your UI related tasks need to be done in the main thread. Here you are presenting the alert inside a closure which executes in a background thread, thats the problem. You need to call the main queue and present alert in that block.
EDIT:
Just put your alert code in this-
For Swift 3-
Get main queue asynchronously
DispatchQueue.main.async {
//Code Here
}
Get main queue synchronously
DispatchQueue.main.sync {
//Code Here
}
Every UI update has to be on main thread:
#IBAction func loginbutton(_ sender: Any) {
let myUrl = NSURL(string: "http://www.shreetechnosolution.com/funded/ngo_login.php")
let request = NSMutableURLRequest(url:myUrl! as URL)
request.httpMethod = "POST"// Compose a query string
let postString = "uname=\(textfieldusername.text!)&password=\(textfieldpassword.text!)";
request.httpBody = postString.data(using: String.Encoding.utf8)
let task = URLSession.shared.dataTask(with: request as URLRequest){ data , response , error in
if error != nil
{
DispatchQueue.main.async {
let alert = UIAlertController(title: "Alert Box !", message: "Login Failed", preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "OK", style: .default, handler: nil))
// Present Alert Controller
self.present(alert, animated: true, completion: nil)
}
return
}
// You can print out response object
print("*****response = \(String(describing: response))")
let responseString = NSString(data: data! , encoding: String.Encoding.utf8.rawValue )
if ((responseString?.contains("")) == nil) {
print("incorrect - try again")
DispatchQueue.main.async {
let alert = UIAlertController(title: "Try Again", message: "Username or Password Incorrect", preferredStyle: .alert)
let yesAction = UIAlertAction(title: "Nochmalversuchen", style: .default) { (action) -> Void in }
// Add Actions
alert.addAction(yesAction)
// Present Alert Controller
self.present(alert, animated: true, completion: nil)
}
}
else {
print("correct good")
}
print("*****response data = \(responseString!)"
do {
//create json object from data
if let json = try JSONSerialization.jsonObject(with: data!, options: .mutableContainers) as? NSDictionary {
if let email = json["UserName"] as? String,
let password1 = json["passowrd"] as? String {
print ("Found User id: called \(email)")
}
let msg = (json.value(forKey: "message") as! NSString!) as String
let id = (json.value(forKey: "NgoId") as! NSString!) as String
DispatchQueue.main.async {
self.alert = UIAlertController(title: "Alert Box!", message: "\(msg)", preferredStyle: .alert)
print("the alert\(self.alert)")
self.action = UIAlertAction(title: "OK", style: .default) { (action) -> Void in
let viewControllerYouWantToPresent = self.storyboard?.instantiateViewController(withIdentifier: "pass1") as! ViewControllerngodetails
viewControllerYouWantToPresent.temp1 = self.id
self.present(viewControllerYouWantToPresent, animated: true, completion: nil)
}
self.alert.addAction(self.action)
self.present(self.alert, animated: true, completion: nil)
}
}
}catch let error {
print(error)
}
}
task.resume()
}
There are two ways how to sign up to my iOS app. First option is using mysql/php (user types email,username,password and I store that in mysql database.
Second option is log in using Facebook and here starts my problem , because I need to have userId, which I can get from Facebook, but I also have an Id in my MySQL database(every user should have his own Id).
So my question is what would you recommend me to do. I have tried to store Facebook user to mysql so he received his unique Id.(but then there were empty columns like password, because Facebook user does not need password).
This is my Facebook sign in (when I sign in with my Facebook account it is ok because my Facebook id Is a pretty high number):
#IBAction func btnFBLoginPressed(sender: AnyObject) {
loadingIndicator.startAnimating()
FBSDKLoginManager().logInWithReadPermissions(["public_profile", "email"],
fromViewController:self,
handler: { (result:FBSDKLoginManagerLoginResult!, error:NSError!) -> Void in
if (error == nil){
self.getFBUserData()
self.loadingIndicator.stopAnimating()
}else{
self.loadingIndicator.stopAnimating()
let myAlert = UIAlertController(title: "Alert!", message: error.localizedDescription, preferredStyle: .Alert)
let okAction = UIAlertAction(title: "Ok", style: .Default, handler: nil)
myAlert.addAction(okAction)
self.presentViewController(myAlert, animated: true, completion: nil)
print(error.localizedDescription)
print("error")
return
}
})
}
func getFBUserData(){
if((FBSDKAccessToken.currentAccessToken()) != nil){
FBSDKGraphRequest(graphPath: "me", parameters: ["fields": "id, name, first_name, last_name, picture.type(large), email"]).startWithCompletionHandler({ (connection, result, error) -> Void in
if (error == nil){
print(result)
print(result["name"])
print(result["id"])
NSUserDefaults.standardUserDefaults().setObject(result["name"]!, forKey: "username")
NSUserDefaults.standardUserDefaults().setObject(result["id"]!, forKey: "userId")
NSUserDefaults.standardUserDefaults().synchronize()
let firstPage = self.storyboard?.instantiateViewControllerWithIdentifier("ViewController")as! ViewController
let appDelegate = UIApplication.sharedApplication().delegate
appDelegate?.window??.rootViewController = firstPage
}else{
let myAlert = UIAlertController(title: "Alert!", message: error?.localizedDescription, preferredStyle: .Alert)
let okAction = UIAlertAction(title: "Ok", style: .Default, handler: nil)
myAlert.addAction(okAction)
self.presentViewController(myAlert, animated: true, completion: nil)
print(error.localizedDescription)
print("error")
return
}
})
}
}
This is MySQL sign in:
#IBAction func loginTapped(sender: AnyObject) {
let userEmail = emailTextField.text
let userPassword = passwordTextField.text
if (userEmail!.isEmpty||userPassword!.isEmpty){
let myAlert = UIAlertController(title: "Alert", message: "All fields must be filled out", preferredStyle: .Alert)
let okAction = UIAlertAction(title: "Ok", style: .Default, handler: nil)
myAlert.addAction(okAction)
self.presentViewController(myAlert, animated: true, completion: nil)
return
}
self.loadingIndicator.startAnimating()
let myUrl = NSURL(string: "http://localhost/~myPc/userSignIn.php")!
let request = NSMutableURLRequest(URL: myUrl)
request.HTTPMethod = "POST"
let postString = "userEmail=\(userEmail!)&userPassword=\(userPassword!)"
request.HTTPBody = postString.dataUsingEncoding(NSUTF8StringEncoding)
NSURLSession.sharedSession().dataTaskWithRequest(request, completionHandler: { (data:NSData?, response:NSURLResponse?, error:NSError?) in
dispatch_async(dispatch_get_main_queue()){
if (error != nil){
let myAlert = UIAlertController(title: "Alert", message: error?.localizedDescription, preferredStyle: .Alert)
let okAction = UIAlertAction(title: "Ok", style: .Default, handler: nil)
myAlert.addAction(okAction)
self.presentViewController(myAlert, animated: true, completion: nil)
self.loadingIndicator.stopAnimating()
return
}
do {
let json = try NSJSONSerialization.JSONObjectWithData(data!, options: .MutableContainers) as? NSDictionary
if let parseJson = json {
let userId = parseJson["userId"] as? String
if userId != nil{
NSUserDefaults.standardUserDefaults().setObject(parseJson["username"], forKey: "username")
NSUserDefaults.standardUserDefaults().setObject(parseJson["userId"], forKey: "userId")
NSUserDefaults.standardUserDefaults().synchronize()
let firstPage = self.storyboard?.instantiateViewControllerWithIdentifier("ViewController")as! ViewController
let appDelegate = UIApplication.sharedApplication().delegate
appDelegate?.window??.rootViewController = firstPage
}else{
let userMessage = parseJson["message"] as? String
let myAlert = UIAlertController(title: "Alert", message: userMessage, preferredStyle: .Alert)
let okAction = UIAlertAction(title: "Ok", style: .Default, handler: nil)
myAlert.addAction(okAction)
self.presentViewController(myAlert, animated: true, completion: nil)
self.loadingIndicator.stopAnimating()
}
self.loadingIndicator.stopAnimating()
}
} catch {
print(error)
}
}
}).resume()
}
I am using the Heimdallr.swift repository in my swift app to login with OAuth2 Password grant. But after getting the "success" message, i can still not access the protected resources. Do anyone know how to save the token that you receive or what the problem might be?
#IBAction func loginButton(sender: UIButton) {
let username: String = usernameTextfield.text!;
let password: String = passwordTextfield.text!;
let tokenURL = NSURL(string: "http://challyme.dk:8888/index.php/api/v1.1/oauth/access_token")!
let identifier = "id0"
let secret = "secret0"
let credentials = OAuthClientCredentials(id: identifier, secret: secret)
let heimdall = Heimdallr(tokenURL: tokenURL, credentials: credentials)
heimdall.requestAccessToken(username: username, password: password) { result in
switch result {
case .Success:
self.callUserInfo(heimdall)
dispatch_async(dispatch_get_main_queue()) {
let mainStoryboard = UIStoryboard(name: "Main", bundle: NSBundle.mainBundle())
let vc : UIViewController = mainStoryboard.instantiateViewControllerWithIdentifier("LogedInView") as UIViewController
self.presentViewController(vc, animated: true, completion: nil)
}
case .Failure:
dispatch_async(dispatch_get_main_queue()) {
print("Wrong password or username")
let alertView = UIAlertController(title: "Alert", message: "You entered the wrong username or password", preferredStyle: .Alert)
alertView.addAction(UIAlertAction(title: "Ok", style: .Default, handler: nil))
self.presentViewController(alertView, animated: true, completion: nil)
}
}
}
}
The method that should display the protected resources:
func callUserInfo(heimdall: Heimdallr) {
let urlPath = "http://linkToResources"
let url: NSURL = NSURL(string: urlPath)!
let session = NSURLSession.sharedSession()
let request = NSMutableURLRequest(URL: url)
heimdall.authenticateRequest(request, completion: { result in
switch result {
case .Success(let request):
let task = session.dataTaskWithRequest(request) { data, response, error in
let json = JSON(data: data!);
print(response!.description);
if response != nil {
print(json);
} else {
print(json[999].error) // "Array[999] is out of bounds"
}
}
task.resume()
case .Failure:
print("failure")
}
})
}
Best regards
Anders B. Christensen