iOs - unrecognized selector sent to instance on TextAction - ios

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:

Related

How to implement a YesNo box as a ViewController method?

I would like to add a method to my ViewController that shows a message with text as an alert with a Yes and a No button. The result should be of type Bool (Yes/No).
What I have tried is the following:
func YesNoBox(msg: String) -> Bool
{
var retVal = false
let alert = UIAlertController(title: "", message: msg, preferredStyle: .alert)
let action_yes = UIAlertAction(title: "Yes", style: .default, handler:
{ _ in NSLog("The \"Yes\" alert occured."); retVal = true })
let action_no = UIAlertAction(title: "No", style: .cancel, handler:
{ _ in NSLog("The \"No\" alert occured."); retVal = false })
alert.addAction(action_yes)
alert.addAction(action_no)
self.present(alert, animated: true, completion: nil)
return retVal
}
However, the value of retVal is always false. If I was in C/C++, I guess I could resolve this issue with a pointer, but this is Swift (and I am pretty new to this).
Any idea anyone how I could get this working?
EDIT: The problem that I have is the following. On a ViewController I have a TextField. When I tap on the text field, the app should ask the user whether they want to paste the text from the clipboard. If yes, paste, otherwise give the TextField the focus (i.e. let the cursor blink in it). I tried to do this with 'textFieldShouldBeginEditing' and in this method I display the YesNoBox. The problem is that the TextField never gets the focus after the YesNoBox is closed. And when I use 'becomeFirstResponder()' after the Box call, the app freezes. I don't know what to do?
Use a completion
func yesNoBox(msg: String,completion:#escaping(Bool) -> ())
{
let alert = UIAlertController(title: "", message: msg, preferredStyle: .alert)
let action_yes = UIAlertAction(title: "Yes", style: .default, handler:
{ _ in
NSLog("The \"Yes\" alert occured.");
completion(true)
})
let action_no = UIAlertAction(title: "No", style: .cancel, handler:
{ _ in
NSLog("The \"No\" alert occured.");
completion(false)
})
alert.addAction(action_yes)
alert.addAction(action_no)
self.present(alert, animated: true, completion: nil)
}
call
yesNoBox(msg:"someMessage") { yes in
if yes {
// do yes action
}
else {
// do no action
}
}
2 Callbacks:
This function has 2 completions ( imagine we have a function that uploads an image and notifies the progress with a completion and another 1 to say done )
func uploadImage(data: Data,progress:#escaping(Float) -> (),completion:#escaping(Bool) -> ()) {
// implementation here
}
To call
self.uploadImage(someData) { progress in
print(progress)
}) { done in
print(done)
}
This can be achieved with completion handlers.
func showAlertWithOptions(title: String, message: String, completionHandler: #escaping (Bool) -> Void) {
let alert = UIAlertController(title: title, message: message, preferredStyle: .alert)
let action_yes = UIAlertAction(title: "Yes", style: .default, handler: { _ in
completionHandler(true)
})
let action_no = UIAlertAction(title: "No", style: .cancel, handler: { _ in
completionHandler(false)
})
alert.addAction(action_yes)
alert.addAction(action_no)
self.present(alert, animated: true, completion: nil)
}
Now call the function and add any other functions or actions that you want to perform depending on the action selected.
showAlertWithOptions(title: "Any title", message: "Any message") { success in
if success {
NSLog("The \"Yes\" alert occured.")
} else {
NSLog("The \"No\" alert occured.")
}
}

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

deallocating is not allowed when attempting to load the view

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)
}

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)
}

Parse Password reset function

I am trying to use the password reset for parse in my ios app and I can't seem to find any tutorial on the best method in swift on how to implement this into a button action but find nothing.
Anyone know a great place to look?
This is what I have so far
#IBAction func resetPassword(sender: AnyObject) {
[PFUser requestPasswordResetForEmailInBackground:
self.loginEmail.text
block:^(BOOL succeeded, NSError *error)
{
[APP.hud hide:YES];
if (!succeeded)
{
NSString *msg = #"Could not connect. Try again later.";
[UIAlertView ok:msg];
return;
}
[UIAlertView minimalistMessageFor:3.0
title:nil
message:#"Your password has been sent to your email address."
then:^{ }];
[self begin];
}];
}
I get a Expected expression in container literal error on this one on the PFUser line.
I use the following in the app I'm working on, which pop ups a alert box to enter your email and confirms the result in a new alert box:
#IBAction func resetPasswordPressed(sender: AnyObject) {
let titlePrompt = UIAlertController(title: "Reset password",
message: "Enter the email you registered with:",
preferredStyle: .Alert)
var titleTextField: UITextField?
titlePrompt.addTextFieldWithConfigurationHandler { (textField) -> Void in
titleTextField = textField
textField.placeholder = "Email"
}
let cancelAction: UIAlertAction = UIAlertAction(title: "Cancel", style: .Default, handler: nil)
titlePrompt.addAction(cancelAction)
titlePrompt.addAction(UIAlertAction(title: "Reset", style: .Destructive, handler: { (action) -> Void in
if let textField = titleTextField {
self.resetPassword(textField.text)
}
}))
self.presentViewController(titlePrompt, animated: true, completion: nil)
}
func resetPassword(email : String){
// convert the email string to lower case
let emailToLowerCase = email.lowercaseString
// remove any whitespaces before and after the email address
let emailClean = emailToLowerCase.stringByTrimmingCharactersInSet(NSCharacterSet.whitespaceCharacterSet())
PFUser.requestPasswordResetForEmailInBackground(emailClean) { (success, error) -> Void in
if (error == nil) {
let success = UIAlertController(title: "Success", message: "Success! Check your email!", preferredStyle: .Alert)
let okButton = UIAlertAction(title: "OK", style: .Default, handler: nil)
success.addAction(okButton)
self.presentViewController(success, animated: false, completion: nil)
}else {
let errormessage = error!.userInfo!["error"] as! NSString
let error = UIAlertController(title: "Cannot complete request", message: errormessage as String, preferredStyle: .Alert)
let okButton = UIAlertAction(title: "OK", style: .Default, handler: nil)
error.addAction(okButton)
self.presentViewController(error, animated: false, completion: nil)
}
}
}
It's also smart to convert the email users register with to lowercase before you sync it with parse in a similar way as I show with the reset method.
If you want to put in a activity indicator, so that users see that the app is busy in between the actions, create the following two methods and call Pause() in the Reset action and Restore() just before or after the if/else in the resetPassword method. Also include the following class variable:
var activityIndicator: UIActivityIndicatorView = UIActivityIndicatorView()
func pause(){
activityIndicator = UIActivityIndicatorView(frame: CGRectMake(0, 0, 50, 50))
activityIndicator.center = self.view.center
activityIndicator.hidesWhenStopped = true
activityIndicator.activityIndicatorViewStyle = UIActivityIndicatorViewStyle.Gray
view.addSubview(activityIndicator)
activityIndicator.startAnimating()
UIApplication.sharedApplication().beginIgnoringInteractionEvents()
}
func restore(){
activityIndicator.stopAnimating()
UIApplication.sharedApplication().endIgnoringInteractionEvents()
}
It looks like you are mixing up swift with objective-c. I'm assuming that you are in a swift class. Try the following:
#IBAction func resetPassword(sender: AnyObject) {
PFUser.requestPasswordResetForEmailInBackground(self.loginEmail.text)
var alert = UIAlertController(title: nil, message: "Your password has been sent to your email address.", preferredStyle: UIAlertControllerStyle.Alert)
alert.addAction(UIAlertAction(title: "Ok", style: UIAlertActionStyle.Default, handler: nil))
self.presentViewController(alert, animated: true, completion: nil)
}
I had a similar problem, the problem is that the doc is apparently not updated on that
PFUser.requestPasswordResetForEmailInBackground("email#example.com")
The following thing worked for me
PFUser.requestPasswordResetForEmailInBackground("email#example.com", nil)
Hope that this will help

Resources