deallocating is not allowed when attempting to load the view - ios

I am using swift to send a message to my server, however, I am not able to get an alert popup to happen when it is over. Here is the code.
func sendSimpleCommand(siteId: Int, command: String) -> Int {
Alamofire.request(.GET, commandUrl, parameters: ["site": siteId, "command": command, "device": "ios"])
.responseJSON { response in
//print(response.result) // result of response serialization
switch response.result {
case .Success(_):
print("success code back from api server for command sent")
let alertView = UIAlertController(title: "Command Sent", message: "Your \(command) has been sent.", preferredStyle: .Alert)
let alertAction = UIAlertAction(title: "OK", style: .Default) { _ in
}
alertView.addAction(alertAction)
case .Failure(_):
print("FAIL code back from api server for command sent")
let alertView = UIAlertController(title: "Connect Error", message: "Network error, please try again", preferredStyle: .Alert)
let alertAction = UIAlertAction(title: "OK", style: .Default) { _ in
}
alertView.addAction(alertAction)
}
}
return 1
}
#IBAction func startButtonTouch(sender: UIButton) {
let helper = HelperActions()
let site = ActiveSite.sharedInstance.siteObject
let command: String = "start"
sendSimpleCommand(site.id , command: command)
}
Now when I run it, the network communication happens correctly but then I get an error and the alert window never shows up.
Attempting to load the view of a view controller while it is deallocating is not allowed and may result in undefined behavior

Just add this single line on top of your code to make an global request of UIAlertController.
As in swift we don't have to deallocate any views. Swift language handels it on their side.
let alertView : UIAlertController?
remove all declaration of alertView in the class
Edit
func sendSimpleCommand(siteId: Int, command: String) -> Int {
Alamofire.request(.GET, commandUrl, parameters: ["site": siteId, "command": command, "device": "ios"])
.responseJSON { response in
//print(response.result) // result of response serialization
switch response.result {
case .Success(_):
print("success code back from api server for command sent")
alertView = UIAlertController(title: "Command Sent", message: "Your \(command) has been sent.", preferredStyle: .Alert)
let alertAction = UIAlertAction(title: "OK", style: .Default) { _ in
}
alertView.addAction(alertAction)
case .Failure(_):
print("FAIL code back from api server for command sent")
alertView = UIAlertController(title: "Connect Error", message: "Network error, please try again", preferredStyle: .Alert)
let alertAction = UIAlertAction(title: "OK", style: .Default) { _ in
}
alertView.addAction(alertAction)
}
}
return 1
}
#IBAction func startButtonTouch(sender: UIButton) {
let helper = HelperActions()
let site = ActiveSite.sharedInstance.siteObject
let command: String = "start"
sendSimpleCommand(site.id , command: command)
}

Related

Assign custom ParameterEncoding per viewcontroller for Alamofire Request

UPDATED Question:
At first my issue was about assigning a custom ParameterEncoding per ViewController based on the HTTP.Method request, I found a solution and added the string in the Alamofire.request then added import Alamofire to the head of each ViewController which helped calling JSONEncoding and URLEncoding and changed the way of call by adding the header to the request as well to avoid 401 unauthorized error.
func callingHttpRequest(params:Dictionary<String,Any>, apiname:String,cuurentView:UIViewController,method:HTTPMethod, taskCallback: #escaping (Int,
AnyObject?) -> Void) {
let urlString = HOST_NAME + apiname
print("url",urlString)
print("params", params)
Alamofire.request(urlString,method: method,parameters:params).validate().responseJSON { response in
switch response.result {
case .success(let resultData):
taskCallback(1,resultData as AnyObject)
let returnData = String(data: response.data! , encoding: .utf8)
print("returnData" ,returnData!)
print("request URL", response.request!)
break
case .failure(let error):
let returnData = String(data: response.data! , encoding: .utf8)
print("returnData" ,returnData!)
print("request URL", response.request!)
if !Connectivity.isConnectedToInternet(){
NetworkManager.sharedInstance.dismissLoader()
cuurentView.view.isUserInteractionEnabled = true
let AC = UIAlertController(title: "Warning", message: error.localizedDescription, preferredStyle: .alert)
let okBtn = UIAlertAction(title: "Retry", style: .default, handler: {(_ action: UIAlertAction) -> Void in
taskCallback(2, "" as AnyObject)
})
let noBtn = UIAlertAction(title: "Cancel", style: .destructive, handler: {(_ action: UIAlertAction) -> Void in
})
AC.addAction(okBtn)
AC.addAction(noBtn)
cuurentView.present(AC, animated: true, completion: { _ in })
}
else{
let errorCode:Int = error._code;
if errorCode != -999 && errorCode != -1005{
NetworkManager.sharedInstance.dismissLoader()
cuurentView.view.isUserInteractionEnabled = true
let AC = UIAlertController(title: "Warning", message: error.localizedDescription, preferredStyle: .alert)
let okBtn = UIAlertAction(title: "Retry", style: .default, handler: {(_ action: UIAlertAction) -> Void in
taskCallback(2, "" as AnyObject)
})
let noBtn = UIAlertAction(title: "Cancel", style: .destructive, handler: {(_ action: UIAlertAction) -> Void in
})
AC.addAction(okBtn)
AC.addAction(noBtn)
cuurentView.present(AC, animated: true, completion: { _ in })
}else if errorCode == -1005{
NetworkManager.sharedInstance.dismissLoader()
taskCallback(2, "" as AnyObject)
}
}
break;
}
}
Now what's really pissing me off is the response of the request, the app is made with user login so each time the app runs it will check if the user logged in or not. When the HTTP request is sent the response returns with SQL Query added to JSON if the user is logged in as below
Failure returnData string(84) "SELECT * FROM customer where LOWER(user) = 'helloworld' AND status = '1'"
{"success":true,"data":[{,,,,,"}
This is causing a failure response and and error
Warning: JSON could not be serialized because of error: The data couldn't be read because it isn't in the correct format.
This is really insane why the response is returning a SQL Query while it shouldn't. That wasn't happening before I customized the header and encoding of the Alamofire.request.
Any way faced such issue can hep please!
P.S.: The response has 200 OK HTTP Response but with failure Data Response

Want to use UIAlertController inside an Alamofire reponseJSON block

The UIAlertControllers are not being executed or are not being displayed. If i solely write a print statement then there's output in the console but now the print statements are also not being executed(if i write them along with the UIAlertControllers like in the code i wrote below).
Alamofire.request(some_url, method: .post, parameters: data, encoding: URLEncoding.default, headers: nil).responseJSON{
response in
let json = JSON(response.result.value)
print(json)
self.eventid = json[0]["EventRegID"].stringValue
if !json[0]["AuthKeyError"].exists(){
if !json[0]["ExceptionOccured"].exists(){
if !json[0]["RegistrationFailed"].exists() {
if !json[0]["EventInHold"].exists() {
if json[0]["RegistrationSuccess"].exists() {
let alertController = UIAlertController(title: "", message: json[0]["RegistrationSuccess"].stringValue, preferredStyle: .alert)
let no1Action = UIAlertAction(title: "OK", style: .default) { (action) -> Void in
print("The user has registered successfully")
}
alertController.addAction(no1Action)
}
else{
}
}
else {
let alertController = UIAlertController(title: "", message: "Event is on hold.", preferredStyle: .alert)
let no2Action = UIAlertAction(title: "OK", style: .default) { (action) -> Void in
print("The event is on hold.")
}
let yes2Action = UIAlertAction(title: "GO", style: .default) { (action) -> Void in
self.performSegue(withIdentifier: "bullshit", sender: self)
}
alertController.addAction(no2Action)
alertController.addAction(yes2Action)
}
}
else {
print("Registration failed due to connection issues. Please login.")
let alertController = UIAlertController(title: "", message: "Registration failed", preferredStyle: .alert)
let no3Action = UIAlertAction(title: "OK", style: .default) { (action) -> Void in
print("The registration failed")
}
alertController.addAction(no3Action)
}
}
else {
print("There's some problem with the database")
let alertController = UIAlertController(title: "", message: "Some problem with the server", preferredStyle: .alert)
let no4Action = UIAlertAction(title: "OK", style: .default) { (action) -> Void in
print("The user has registered successfully")
}
alertController.addAction(no4Action)
}
}
else {
print("AuthKeyError")
let alertController = UIAlertController(title: "", message: "Auth key error", preferredStyle: .alert)
let no5Action = UIAlertAction(title: "OK", style: .default) { (action) -> Void in
print("AAUTH KEY ERROR")
}
alertController.addAction(no5Action)
}
}
}
else {
print("not ok")
}
}
you need to present the alertcontroller after addAction
presentViewController(alertController, animated: true, completion: nil)
maybe you have to present it in a new operation
OperationQueue.main.addOperation {
presentViewController(alertController, animated: true, completion: nil)
}

Handling Errors in New Firebase and Swift

I'm trying to add error handling in creating user button in iOS project using swift and firebase:
Here's the code for the button:
#IBAction func Register(sender: AnyObject) {
if NameTF.text == "" || EmailTF.text == "" || PasswordTF.text == "" || RePasswordTF == "" || PhoneTF.text == "" || CityTF.text == ""
{
let alert = UIAlertController(title: "عذرًا", message:"يجب عليك ملىء كل الحقول المطلوبة", preferredStyle: .Alert)
alert.addAction(UIAlertAction(title: "نعم", style: .Default) { _ in })
self.presentViewController(alert, animated: true){}
} else {
if PasswordTF.text != RePasswordTF.text {
let alert = UIAlertController(title: "عذرًا", message:"كلمتي المرور غير متطابقتين", preferredStyle: .Alert)
alert.addAction(UIAlertAction(title: "نعم", style: .Default) { _ in })
self.presentViewController(alert, animated: true){}
} else {
FIRAuth.auth()?.createUserWithEmail(EmailTF.text!, password: PasswordTF.text!, completion: { user, error in
print(error)
if error != nil {
let errorCode = FIRAuthErrorNameKey
switch errorCode {
case "FIRAuthErrorCodeEmailAlreadyInUse":
let alert = UIAlertController(title: "عذرًا", message:"الإيميل مستخدم", preferredStyle: .Alert)
alert.addAction(UIAlertAction(title: "نعم", style: .Default) { _ in })
self.presentViewController(alert, animated: true){}
case "FIRAuthErrorCodeUserNotFound":
let alert = UIAlertController(title: "عذرًا", message:"المستخدم غير موجود", preferredStyle: .Alert)
alert.addAction(UIAlertAction(title: "نعم", style: .Default) { _ in })
self.presentViewController(alert, animated: true){}
case "FIRAuthErrorCodeInvalidEmail":
let alert = UIAlertController(title: "عذرًا", message:"الإيميل غير صحيح", preferredStyle: .Alert)
alert.addAction(UIAlertAction(title: "نعم", style: .Default) { _ in })
self.presentViewController(alert, animated: true){}
case "FIRAuthErrorCodeNetworkError":
let alert = UIAlertController(title: "عذرًا", message:"خطأ في الاتصال بالانترنت", preferredStyle: .Alert)
alert.addAction(UIAlertAction(title: "نعم", style: .Default) { _ in })
self.presentViewController(alert, animated: true){}
default:
let alert = UIAlertController(title: "عذرًا", message:"خطأ غير معروف", preferredStyle: .Alert)
alert.addAction(UIAlertAction(title: "نعم", style: .Default) { _ in })
self.presentViewController(alert, animated: true){}
}
} else {
FIRAuth.auth()?.signInWithEmail(self.EmailTF.text!, password: self.PasswordTF.text!, completion: { (user: FIRUser?, error: NSError?) in
if let error = error {
print(error.localizedDescription)
} else {
self.ref.child("UserProfile").child(user!.uid).setValue([
"email": self.EmailTF.text!,
"name" : self.NameTF.text!,
"phone": self.PhoneTF.text!,
"city" : self.CityTF.text!,
])
print("Sucess")
// self.performSegueWithIdentifier("SignUp", sender: nil)
}
})
} //else
})
} //Big else
} //Big Big else
}
}//end of
I'm not sure if the syntax of the errors in switch statement is correct or not!
Because when I tested it in the simulator it always gives me the defualt case which is unknown error!
+
I could not find the syntax in the documentation:
https://firebase.google.com/docs/auth/ios/errors
So, What's the correct syntax to add error handling using new firebase and swift!
I've actually just struggled with this for quite a bit of time and found what the issue was. I've tried the code posted in an answer above and the error.code line gave me an error. It did work with error._code though. In other words, credit for the original answer to Paul with a slight modificaiton. Here's my final code (I will edit it for all errors though):
if let errCode = AuthErrorCode(rawValue: error!._code) {
switch errCode {
case .errorCodeInvalidEmail:
print("invalid email")
case .errorCodeEmailAlreadyInUse:
print("in use")
default:
print("Create User Error: \(error)")
}
}
Updated for Swift 4 + Firebase 4 + UIAlertController
extension AuthErrorCode {
var errorMessage: String {
switch self {
case .emailAlreadyInUse:
return "The email is already in use with another account"
case .userNotFound:
return "Account not found for the specified user. Please check and try again"
case .userDisabled:
return "Your account has been disabled. Please contact support."
case .invalidEmail, .invalidSender, .invalidRecipientEmail:
return "Please enter a valid email"
case .networkError:
return "Network error. Please try again."
case .weakPassword:
return "Your password is too weak. The password must be 6 characters long or more."
case .wrongPassword:
return "Your password is incorrect. Please try again or use 'Forgot password' to reset your password"
default:
return "Unknown error occurred"
}
}
}
extension UIViewController{
func handleError(_ error: Error) {
if let errorCode = AuthErrorCode(rawValue: error._code) {
print(errorCode.errorMessage)
let alert = UIAlertController(title: "Error", message: errorCode.errorMessage, preferredStyle: .alert)
let okAction = UIAlertAction(title: "Ok", style: .default, handler: nil)
alert.addAction(okAction)
self.present(alert, animated: true, completion: nil)
}
}
}
Usage example:
Auth.auth().signIn(withEmail: email, password: password, completion: { (user, error) in
if error != nil {
print(error!._code)
self.handleError(error!) // use the handleError method
return
}
//successfully logged in the user
})
Even though this has been answered correctly, wanted to share a nice implementation for this we added to our project.
This can be done for other error types as well, but we just needed it for the FIRAuthErrorCodes.
If you extend FIRAuthErrorCode to have a variable errorMessage of type string, you can have your own error messages for the users:
extension FIRAuthErrorCode {
var errorMessage: String {
switch self {
case .errorCodeEmailAlreadyInUse:
return "The email is already in use with another account"
case .errorCodeUserDisabled:
return "Your account has been disabled. Please contact support."
case .errorCodeInvalidEmail, .errorCodeInvalidSender, .errorCodeInvalidRecipientEmail:
return "Please enter a valid email"
case .errorCodeNetworkError:
return "Network error. Please try again."
case .errorCodeWeakPassword:
return "Your password is too weak"
default:
return "Unknown error occurred"
}
}
}
You could customize only some as we have above and group the rest under "Unknown error".
With this extension you can handle an error as shown in Vladimir Romanov's answer:
func handleError(_ error: Error) {
if let errorCode = FIRAuthErrorCode(rawValue: error._code) {
// now you can use the .errorMessage var to get your custom error message
print(errorCode.errorMessage)
}
}
FIRAuthErrorCode is an int enum not a string enum. Do the following:
if let error = error {
switch FIRAuthErrorCode(rawValue: error.code) !{
case .ErrorCodeInvalidEmail:
More info in this answer.
I am using Swift 5 and Firebase 6.4.0 and for me, none of the above really worked. After trying around a bit I came up with this:
Auth.auth().createUser(withEmail: emailTextfield.text!, password: passwordTextfield.text!) { (user, error) in
if error!= nil{
let alert = UIAlertController(title: "Error", message: error!.localizedDescription, preferredStyle: .alert)
let okAction = UIAlertAction(title: "Ok", style: .default, handler: nil)
alert.addAction(okAction)
self.present(alert,animated: true)
}

iOs - unrecognized selector sent to instance on TextAction

i've some problem with this error :
ProjectName.ViewController textAction:]: unrecognized selector sent to instance 0x7fa60bc3840
The error appears when i try to create an alerte. Here is the code :
#IBAction func trySearch(sender: UIButton) {
self.api.getUser(self.textField.text!) { isResponse in
if (isResponse.count == 0) {
//Still crash HERE.
let alert = UIAlertController(title: "Error", message: "This username doesn't exist", preferredStyle: UIAlertControllerStyle.Alert)
alert.addAction(UIAlertAction(title: "Ok", style: UIAlertActionStyle.Default, handler: nil))
self.presentViewController(alert, animated: true, completion: nil)
}
else {
print("existing username")
}
}
If i comment all the alert code and replace it by a simple print it s works... I really don't understand why... Thank's !
getUser function:
func getUser(user: String, completion: ((isReponse: AnyObject) -> Void)) {
let request = NSMutableURLRequest(URL: NSURL(string: "https://********")!)
request.HTTPMethod = "GET"
request.setValue("Bearer \(self.loadToken())", forHTTPHeaderField: "Authorization")
Alamofire.request(request)
.responseJSON { response in
switch response.result {
case .Success(let JSON):
completion(isReponse: JSON)
case .Failure(let error):
print("Request failed with error: \(error)")
}
}
}
UPDATE : Same error when i click on "Done" of my TextField. + i add the getUser function.
You may be in the wrong thread, since you are presenting the alert within a block, try:
dispatch_async(dispatch_get_main_queue(), { _ in
let alert = UIAlertController(title: "Error", message: "This username doesn't exist", preferredStyle: UIAlertControllerStyle.Alert)
alert.addAction(UIAlertAction(title: "Ok", style: UIAlertActionStyle.Default, handler: nil))
self.presentViewController(alert, animated: true, completion: nil)
})
handler
A block to execute when the user selects the action. This block has no return value and takes the selected action object as its only parameter.
YOU don't assign action here.
Make like this:
UIAlertAction* ok = [UIAlertAction
actionWithTitle:#"OK"
style:UIAlertActionStyleDefault
handler:^(UIAlertAction * action)
{
//Do some thing here
[view dismissViewControllerAnimated:YES completion:nil];
}];
// add action to your alertController
[alert addAction:ok];
https://developer.apple.com/library/ios/documentation/UIKit/Reference/UIAlertAction_Class/#//apple_ref/occ/clm/UIAlertAction/actionWithTitle:style:handler:

present an alertviewcontroller during segue

I have a helper method that prompts an alertviewcontroller on my actual view controller. however, if this happens during a segue. my segue gets cancelled. Any ideas?
AlamoHelper.request(.POST, url: AppDelegate.kbaseUrl + "users/signin", parameters: ["email": String(emailTextField.text!), "password": String(passwordTextField.text!)])
.responseJSON {
response in
switch (response.result) {
case .Success:
var json = JSON(response.result.value!)
if (json["status"] != 200){
AppDelegate.removeCookies()
AppDelegate.isLoggedIn = false
} else {
self.performSegueWithIdentifier("showTabBarController", sender: self)
self.emailTextField.text = ""
self.passwordTextField.text = ""
self.appDelegate.storeCookies()
AppDelegate.isLoggedIn = true
self.addDeviceToken()
}
break
case .Failure:
break
}
}
in my helper, the part where I show the alert controller is this
if json["status"].intValue == 500 {
let alert = UIAlertController(title: "Unknown error", message: "Please try again later. If problem persists, please contact Offpeak support", preferredStyle: .Alert)
let okAction = UIAlertAction(title: "Ok", style: .Cancel, handler: nil)
alert.addAction(okAction)
AlamoHelper.getCurrentViewController().presentViewController(alert, animated: true, completion: nil)
}

Resources