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()
}
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 need the variable 'response' to be taken from "dataTaskWithRequest". Right now, 'response' is not found because it is outside of the brackets. How can i make sure to pass the response variable to the UIAlert? Thanks
Here is my code:
#IBAction func buttonCreateAccount(sender: AnyObject) {
let request = NSMutableURLRequest(URL: NSURL(string: "http://www.example.com/createaccount.php")!)
request.HTTPMethod = "POST"
let postString = "user_name=\(username.text!)&email=\(email.text!)&password=\(password.text!)"
request.HTTPBody = postString.dataUsingEncoding(NSUTF8StringEncoding)
let task = NSURLSession.sharedSession().dataTaskWithRequest(request) {
data, response, error in
if error != nil {
print("error=\(error)")
return
}
print("response = \(response)")
let response = String(data: data!, encoding: NSUTF8StringEncoding)
print("responseString = \(response)")
}
task.resume()
//problem is here. 'response' variable cannot be taken from above. i need it to be taken from above.
if response == "Username taken" {
if let getModernAlert: AnyClass = NSClassFromString("UIAlertController") { // iOS 8
let myAlert: UIAlertController = UIAlertController(title: "Registration", message: response, preferredStyle: .Alert)
myAlert.addAction(UIAlertAction(title: "OK", style: .Default, handler: nil))
self.presentViewController(myAlert, animated: true, completion: nil)
} else { // iOS 7
let alert: UIAlertView = UIAlertView()
alert.delegate = self
alert.title = "Registration"
alert.message = "Testing"
alert.addButtonWithTitle("OK")
alert.show()
}
} else {
if let getModernAlert: AnyClass = NSClassFromString("UIAlertController") { // iOS 8
let myAlert: UIAlertController = UIAlertController(title: "Registration", message: response, preferredStyle: .Alert)
myAlert.addAction(UIAlertAction(title: "OK", style: .Default, handler: nil))
self.presentViewController(myAlert, animated: true, completion: nil)
} else { // iOS 7
let alert: UIAlertView = UIAlertView()
alert.delegate = self
alert.title = "Registration"
alert.message = "Testing"
alert.addButtonWithTitle("OK")
alert.show()
self.dismissViewControllerAnimated(true, completion: {});
}
}
}
dataTaskWithRequest runs asynchronously. You will not get the response immediately. Separate it into two functions:
#IBAction func buttonCreateAccount(sender: AnyObject) {
let request = NSMutableURLRequest(URL: NSURL(string: "http://www.example.com/createaccount.php")!)
request.HTTPMethod = "POST"
let postString = "user_name=\(username.text!)&email=\(email.text!)&password=\(password.text!)"
request.HTTPBody = postString.dataUsingEncoding(NSUTF8StringEncoding)
let task = NSURLSession.sharedSession().dataTaskWithRequest(request) {
data, response, error in
if error != nil {
print("error=\(error)")
return
}
print("response = \(response)")
let response = String(data: data!, encoding: NSUTF8StringEncoding)
print("responseString = \(response)")
// Now that the response is ready, call the other function to handle it
handleResponse(response)
}
task.resume()
}
func handleResponse(response: String) {
if response == "Username taken" {
if let getModernAlert: AnyClass = NSClassFromString("UIAlertController") { // iOS 8
let myAlert: UIAlertController = UIAlertController(title: "Registration", message: response, preferredStyle: .Alert)
myAlert.addAction(UIAlertAction(title: "OK", style: .Default, handler: nil))
self.presentViewController(myAlert, animated: true, completion: nil)
} else { // iOS 7
let alert: UIAlertView = UIAlertView()
alert.delegate = self
alert.title = "Registration"
alert.message = "Testing"
alert.addButtonWithTitle("OK")
alert.show()
}
} else {
if let getModernAlert: AnyClass = NSClassFromString("UIAlertController") { // iOS 8
let myAlert: UIAlertController = UIAlertController(title: "Registration", message: response, preferredStyle: .Alert)
myAlert.addAction(UIAlertAction(title: "OK", style: .Default, handler: nil))
self.presentViewController(myAlert, animated: true, completion: nil)
} else { // iOS 7
let alert: UIAlertView = UIAlertView()
alert.delegate = self
alert.title = "Registration"
alert.message = "Testing"
alert.addButtonWithTitle("OK")
alert.show()
self.dismissViewControllerAnimated(true, completion: {});
}
}
}
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 have no idea whats wrong with this function. I'm calling it in viewdidload and it prints the array as blank when I load it on my phone. When I do it in the simulator it fills the array though. Using ObjectMapper if that helps at all.
func getData() {
let myURLString = "http://meetup.x10host.com/api/get_event.php?radius=15"
let myURL = NSURL(string: myURLString)!
var myCardsArray = [Card]()
let mySession = NSURLSession(configuration: NSURLSessionConfiguration.defaultSessionConfiguration())
let myDataTask = mySession.dataTaskWithURL(myURL) { (data, response, error) in
guard error == nil else {
let alertController = UIAlertController(title: "No Connection", message:
"Can't connect to database, perhaps turn on your WiFi?", preferredStyle: UIAlertControllerStyle.Alert)
alertController.addAction(UIAlertAction(title: "Okay", style: UIAlertActionStyle.Default,handler: nil))
self.presentViewController(alertController, animated: true, completion: nil)
return
}
do {
let jsonData = try NSJSONSerialization.JSONObjectWithData(data!, options: NSJSONReadingOptions.AllowFragments)
for someCard in jsonData as! NSArray{
let card = Mapper<Card>().map(someCard)
myCardsArray.append(card!)
self.nameArray.append(card!.titlee!)
self.textArray.append(card!.text!)
self.userArray.append(card!.attending!)
self.latArray.append(card!.latitude!)
self.longArray.append(card!.longitude!)
self.timeArray.append(card!.time!)
self.locTextArray.append(card!.locationText!)
dispatch_async(dispatch_get_main_queue()) {
self.tableView.reloadData()
}
}
} catch {
print("There was an error")
}
}
myDataTask.resume()
print(nameArray)
}