uiAlertController not dismissing someTimes - swift

I have login button which is http get service I run a popUp alert for waiting when user taps on button and I dismiss it when I fetch data.
but some times sucks on loading alert.test it on iPhone 5s but working on simulator properly.what I'm doing wrong??
#IBAction func loginButton(_ sender: Any) {
phone=phoneText.text!
if (validation(phone: phone)){
popUpLoading()
guard let url=URL(string: address+"uSers/checkUser/\(phone)") else{return}
print(url)
var requst=URLRequest(url: url)
requst.httpMethod="GET"
URLSession.shared.dataTask(with: requst, completionHandler: { (data, response, error) in
if let response=response{
//print(response)
}
if let data=data{
do{
let json=try? JSONSerialization.jsonObject(with: data, options:JSONSerialization.ReadingOptions.mutableLeaves) as! [String:Any]
print("jsom : ",json)
DispatchQueue.main.async {
self.popalert.dismiss(animated: true, completion: {
let data=json?["data"] as! String
print("data : ",data)
}
}
popalert variable is declared global
this is pop up alert for waiting :
func popUpLoading(){
DispatchQueue.main.async {
self.popalert = UIAlertController(title: "", message: "wait...", preferredStyle: .alert)
let loadingIndicator = UIActivityIndicatorView(frame: CGRect(x: 10, y: 5, width: 50, height: 50))
loadingIndicator.hidesWhenStopped = true
loadingIndicator.activityIndicatorViewStyle = UIActivityIndicatorViewStyle.gray
loadingIndicator.startAnimating();
self.present(self.popalert, animated: true, completion: nil)
self.popalert.view.addSubview(loadingIndicator)
}
}

You have called the dismiss function which is,
( self.popalert.dismiss(animated: true, completion: { )
inside the response call. So the alert view will be hidden only if you are getting a proper response from the URL.
You should be hiding the alert view in both scenarios
- so use else condition for if statement and dismiss the alertView

Related

Wait Until Function Completes and Segue

Swift is new for me and I stuck at this part. I want to request some data from api when I clicked the button. After that, want to pass the data i get from this function to another view controller. So basicly want to perform segue with this data. However, when I clicked the button, request starts but it directly perform segue to 2. view without any data.
How can I wait for:
videoManager.performRequest(with: videoLinkTextField.text!)
this function to perform segue?
This is my button:
#IBAction func getVideoButtonPressed(_ sender: UIButton) {
if videoLinkTextField.text != nil, videoLinkTextField.text!.contains("tiktok") {
videoManager.performRequest(with: videoLinkTextField.text!)
DispatchQueue.main.async {
self.performSegue(withIdentifier: "GoToVideo", sender: self)
}
} else {
videoLinkTextField.text = ""
let alert = UIAlertController(title: "Error", message: "Please enter a valid link", preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "Ok", style: .default))
present(alert, animated: true, completion: nil)
}
}
Here is my prepare function:
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "GoToVideo" {
DispatchQueue.main.async {
let destionationVC = segue.destination as! ResultViewController
print("Test \(self.videoUrl)")
destionationVC.videoUrl = self.videoUrl
}
}
}
And here is my performRequest function:
func performRequest(with videoUrl: String) {
let request = NSMutableURLRequest(url: NSURL(string: "https://tiktok-downloader-download-videos-without-watermark1.p.rapidapi.com/media-info/?link=\(videoUrl)")! as URL,
cachePolicy: .useProtocolCachePolicy,
timeoutInterval: 10.0)
request.httpMethod = "GET"
request.allHTTPHeaderFields = headers
let session = URLSession.shared
let dataTask = session.dataTask(with: request as URLRequest, completionHandler: { data, _, error in
if error != nil {
self.delegate?.didFailedWithError(error!)
}
if let safeData = data {
if let video = self.parseJSON(safeData) {
self.delegate?.didUpdateVideo(self, video: video)
}
}
})
dataTask.resume()
}
You are asking:
How can I wait for:
videoManager.performRequest(with: videoLinkTextField.text!)
Looks like you may want to use a closure for this method: Check out this article to learn more about closures:
Escaping Closures in Swift
However, I'll also provide you an example of how you'd might want your function to look:
Note, I only added , completion: #escaping () -> Void as a param and added a completion() to indicate where the closure should finish (You can also pass params in a completion block too (e.g: String, Error, etc)
func performRequest(with videoUrl: String, completion: #escaping () -> Void) {
let request = NSMutableURLRequest(url: NSURL(string: "https://tiktok-downloader-download-videos-without-watermark1.p.rapidapi.com/media-info/?link=\(videoUrl)")! as URL,
cachePolicy: .useProtocolCachePolicy,
timeoutInterval: 10.0)
request.httpMethod = "GET"
request.allHTTPHeaderFields = headers
let session = URLSession.shared
let dataTask = session.dataTask(with: request as URLRequest, completionHandler: { data, _, error in
if error != nil {
self.delegate?.didFailedWithError(error!)
}
if let safeData = data {
if let video = self.parseJSON(safeData) {
self.delegate?.didUpdateVideo(self, video: video)
}
}
completion() // finishes the closure
})
dataTask.resume()
}
Then you'll be able to do this:
videoManager.performRequest(with: videoLinkTextField.text!) { _ in
DispatchQueue.main.async {
self.performSegue(withIdentifier: "GoToVideo", sender: self)
}
}
Place segue here
if let video = self.parseJSON(safeData) {
self.delegate?.didUpdateVideo(self, video: video)
DispatchQueue.main.async {
self.performSegue(withIdentifier: "GoToVideo", sender: self)
}
}

completion handler can not dismiss the popAlertController

I have a view controller with a single textView which I get a string from server and set on it.
I call a http-get service in viewDidAppear and I need to show a popUp alert for waiting user till get the string
I do all but I can not dismiss the popalert and app stacks in loading alert
override func viewWillAppear(_ animated: Bool) {
fetchAndPrintEachPerson()
networkReachablity()
popUpLoading() // start showing loading pop alert
getPerson ()
}
override func viewDidLoad() {
super.viewDidLoad()
style()
giftTextFiled.isEnabled = false
}
func popUpLoading(){
popUpAlert = UIAlertController(title: nil, message: "wait ...", preferredStyle: .alert)
let loadingIndicator = UIActivityIndicatorView(frame: CGRect(x: 10, y: 5, width: 50, height: 50))
loadingIndicator.hidesWhenStopped = true
loadingIndicator.activityIndicatorViewStyle = UIActivityIndicatorViewStyle.gray
loadingIndicator.startAnimating();
popUpAlert.view.addSubview(loadingIndicator)
present(popUpAlert, animated: true, completion: nil)
}
func getPerson(){
guard let url=URL(string: "\(address)person/code") else {return}
print(url)
URLSession.shared.dataTask(with: url) { (data, response, error) in
if let res=response {
//print(res)
}
do {
if let dataContent=data {
let con = try? JSONSerialization.jsonObject(with: dataContent, options: []) as? AnyObject
let data = con??["data"] as? AnyObject
let code = data?["code"] as? String
print(code)
// self.popUpAlert.dismiss(animated: true, completion: {
DispatchQueue.main.async(execute: {
//self.giftTextFiled.text=code!
self.giftTextFiled.isEnabled = true
self.popUpAlert.dismiss(animated: true, completion: nil)
})
//})
}else {
let snack=snackBarAlert()
snack.alert(title: "error", color: UIColor.red)
self.popUpAlert.dismiss(animated: true, completion: nil)
}
}catch let err{
print(err)
DispatchQueue.main.async(execute: {
self.popUpAlert.dismiss(animated: true, completion: nil)
})
}
}.resume()
}
update first post.
Try putting that inside view DidLoad & check whether your getting a response from the server other wise it will fall through else block and keep showing the pop up
URLSession.shared.dataTask completion closure is called on non-main thread, which may produce unexpected results for UI. Dispatch your UI code to main thread.
URLSession.shared.dataTask(with: url) { (data, response, error) in
DispatchQueue.main.async {
// Your UI related code
}
}.resume()

use of unresolved identifier 'result' swift 3

I'm writing a login page for my app and i'm getting this error
social media app , xcode 8.3.2 , swift 3
i've tried target membership in file inspector and nothing changed
also I removed test units (UITest and Test) and renew them , it didn't worked either.
at the line 41 I'm getting this error "use of unresolved identifier 'result'"
the picture below explains the code
Picture
import UIKit
class LoginViewController : UIViewController
{
#IBOutlet weak var txt_username: UITextField!
#IBOutlet weak var txt_password: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
#IBAction func btn_log_in_click(_ sender: Any){
let server=MultipartUtility (Url:"http://x.x.x.x/appname-api/user/login/")
//I.m hiding the real ip and details for posting this
server.AddFormField("username", value: txt_username.text)
server.AddFormField("password", value: txt_password.text)
let task = URLSession.shared.dataTask(with: server.execute())
{Data,URLResponse,error in
if error != nil{
print(error as Any)
return
}
do{
let json = try JSONSerialization.jsonObject(with: Data!, options: .allowFragments)
if let json_result = json as? [String: Any]{
let result = json_result ["result"] as? String
if result == "0"
{
DispatchQueue.main.async {
let alert = UIAlertController(title:"Incorrect Username",message : "The username you entered doesn't appear to belong to an account. Please check your username and try again", preferredStyle : .alert)
let alert_action = UIAlertAction(title: "Try Again", style: .default, handler: nil)
alert.addAction(alert_action)
self.present(alert, animated: true, completion: nil)
}
}
}
else{
DispatchQueue.main.async {
UserDefaults.standard.set(result!, forKey: "user_id")
//" use of unresolved identifier 'result' "
let current_view=UIApplication.shared.windows[0] as UIWindow
let new_view=(self.storyboard? .instantiateViewController(withIdentifier: "tab_bar"))! as UIViewController
UIView.transition(from: (current_view.rootViewController? .view)!, to:new_view.view , duration: 0.65, options: .transitionFlipFromRight, completion: {(action) in current_view.rootViewController=new_view
})
}
}
}
catch{
}
}
task.resume()
}
}
if let json_result = json as? [String: Any]
{
let result = json_result ["result"] as? String
if result == "0"
{
DispatchQueue.main.async {
let alert = UIAlertController(title:"Incorrect Username",message : "The username you entered doesn't appear to belong to an account. Please check your username and try again", preferredStyle : .alert)
let alert_action = UIAlertAction(title: "Try Again", style: .default, handler: nil)
alert.addAction(alert_action)
self.present(alert, animated: true, completion: nil)
}
}
else
{
DispatchQueue.main.async {
UserDefaults.standard.set(result!, forKey: "user_id")
//" use of unresolved identifier 'result' "
let current_view=UIApplication.shared.windows[0] as UIWindow
let new_view=(self.storyboard? .instantiateViewController(withIdentifier: "tab_bar"))! as UIViewController
UIView.transition(from: (current_view.rootViewController? .view)!, to:new_view.view , duration: 0.65, options: .transitionFlipFromRight, completion: {(action) in current_view.rootViewController=new_view
})
}
}
}
else{
// Error in jsonSerialization
}

ApplePaybutton is not functioning (ApplePay integration with Stripe)

I am trying to integrate Applepay using Stripe so that users are able to make easy payment. I use heroku account as a backend server. I could add the ApplePay Button on the UI (Please take a look at My Current Storyboard) and tried to configure a pop up check-out window coming from bottom for users to make payment.
My Current UI
However, even if I click the ApplePaybutton, nothing happens. My goal now is making the checkout window when users click the ApplePay Button My Goal UI.
I assume that func beginPayment() is supposed to be called when the button is pressed but doesn't work. I suspect that if (stripePublishableKey == "") { and codes after that is set incorrectly. Any help would be appreciated!
import UIKit
import Stripe
enum STPBackendChargeResult {
case success, failure
}
typealias STPTokenSubmissionHandler = (STPBackendChargeResult?, NSError?) -> Void
class ViewController: UIViewController, PKPaymentAuthorizationViewControllerDelegate {
let stripePublishableKey = "my Stripe PublishableKey"
let backendChargeURLString = "my heroku URL"
let appleMerchantId = "my apple merchand Id"
let shirtPrice : UInt = 1000 // this is in cents
override func viewDidLoad() {
super.viewDidLoad()
//This is the method of making the ApplePayButton( didn't use storyboard)
let button = PKPaymentButton(type: .buy, style: .black)
button.addTarget(self, action: #selector(ViewController.beginPayment(_:)), for: .touchUpInside)
let bw = button.frame.size.width
let bh = button.frame.size.height
let vw = view.frame.size.width
let vh = view.frame.size.height
button.frame = CGRect(origin: CGPoint(x: vw/2 - bw/2, y: vh/2 - bh/2), size: button.frame.size)
view.addSubview(button)
}
//This func is supposed to be called when ApplePayButton is pressed.
func beginPayment(_: UIButton) {
if (stripePublishableKey == "") {
let alert = UIAlertController(
title: "You need to set your Stripe publishable key.",
message: "You can find your publishable key at https://dashboard.stripe.com/account/apikeys .",
preferredStyle: UIAlertControllerStyle.alert
)
let action = UIAlertAction(title: "OK", style: UIAlertActionStyle.default, handler: nil)
alert.addAction(action)
present(alert, animated: true, completion: nil)
return
}
if (appleMerchantId != "") {
let paymentRequest = Stripe.paymentRequest(withMerchantIdentifier: appleMerchantId)
if Stripe.canSubmitPaymentRequest(paymentRequest) {
paymentRequest.paymentSummaryItems = [PKPaymentSummaryItem(label: "Cool shirt", amount: NSDecimalNumber(string: "10.00")), PKPaymentSummaryItem(label: "Stripe shirt shop", amount: NSDecimalNumber(string: "10.00"))]
let paymentAuthVC = PKPaymentAuthorizationViewController(paymentRequest: paymentRequest)
paymentAuthVC.delegate = self
self.present(paymentAuthVC, animated: true, completion: nil)
return
}
} else {
print("You should set an appleMerchantId.")
}
}
func paymentAuthorizationViewController(_ controller: PKPaymentAuthorizationViewController, didAuthorizePayment payment: PKPayment, completion: #escaping ((PKPaymentAuthorizationStatus) -> Void)) {
let apiClient = STPAPIClient(publishableKey: stripePublishableKey)
apiClient.createToken(with: payment, completion: { (token, error) -> Void in
if error == nil {
if let token = token {
self.createBackendChargeWithToken(token, completion: { (result, error) -> Void in
if result == STPBackendChargeResult.success {
completion(PKPaymentAuthorizationStatus.success)
}
else {
completion(PKPaymentAuthorizationStatus.failure)
}
})
}
}
else {
completion(PKPaymentAuthorizationStatus.failure)
}
})
}
func paymentAuthorizationViewControllerDidFinish(_ controller: PKPaymentAuthorizationViewController) {
dismiss(animated: true, completion: nil)
}
func createBackendChargeWithToken(_ token: STPToken, completion: #escaping STPTokenSubmissionHandler) {
if backendChargeURLString != "" {
if let url = URL(string: backendChargeURLString + "/charge") {
let session = URLSession(configuration: URLSessionConfiguration.default)
let request = NSMutableURLRequest(url: url)
request.httpMethod = "POST"
let postBody = "stripeToken=\(token.tokenId)&amount=\(shirtPrice)"
let postData = postBody.data(using: String.Encoding.utf8, allowLossyConversion: false)
session.uploadTask(with: request as URLRequest, from: postData, completionHandler: { data, response, error in
let successfulResponse = (response as? HTTPURLResponse)?.statusCode == 200
if successfulResponse && error == nil {
completion(.success, nil)
} else {
if error != nil {
completion(.failure, error as NSError?)
} else {
completion(.failure, NSError(domain: StripeDomain, code: 50, userInfo: [NSLocalizedDescriptionKey: "There was an error communicating with your payment backend."]))
}
}
}).resume()
return
}
}
completion(STPBackendChargeResult.failure, NSError(domain: StripeDomain, code: 50, userInfo: [NSLocalizedDescriptionKey: "You created a token! Its value is \(token.tokenId). Now configure your backend to accept this token and complete a charge."]))
}
}

How to dismiss a UIAlert with no buttons or interaction in Swift?

I am using a UIAlert to display the string "Loading..." while my iOS application is interacting with a database. Is there any way to pragmatically dismiss it when the action is complete?
code:
let myUrl = NSURL(string: "http://www.test.org/ios.html")
let request = NSMutableURLRequest(URL: myUrl!)
request.HTTPMethod = "POST"
let task = NSURLSession.sharedSession().dataTaskWithRequest(request) {
data, response, error in
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0)) {
let responseString = NSString(data: data!, encoding: NSUTF8StringEncoding)
if error != nil {
print("Error: \(error)")
}
dispatch_async(dispatch_get_main_queue()) {
self.testLabel.text = "\(responseString!)"
// dismiss sendLoading() UIAlert
}
}
}
task.resume()
self.sendLoading()
sendLoading func:
func sendLoading() {
let alertController = UIAlertController(title: "Loading...", message:
"", preferredStyle: UIAlertControllerStyle.Alert)
self.presentViewController(alertController, animated: true, completion: nil)
}
Thank you
Make your alertController as instance variable and when you need to dismiss it just call
self.dismissViewController(alertController, animated:true, completion: nil)
Edit - Adding code.
In your case code would be like -
let alertController : UIAlertController ?
let myUrl = NSURL(string: "http://www.test.org/ios.html")
let request = NSMutableURLRequest(URL: myUrl!)
request.HTTPMethod = "POST"
let task = NSURLSession.sharedSession().dataTaskWithRequest(request) {
data, response, error in
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0)) {
let responseString = NSString(data: data!, encoding: NSUTF8StringEncoding)
if error != nil {
print("Error: \(error)")
}
dispatch_async(dispatch_get_main_queue()) {
self.testLabel.text = "\(responseString!)"
// dismiss sendLoading() UIAlert
self.dismissViewController(alertController!, animated:true, completion: nil)
}
}
}
task.resume()
self.sendLoading()
sendLoading func:
func sendLoading() {
alertController = UIAlertController(title: "Loading...", message:
"", preferredStyle: UIAlertControllerStyle.Alert)
self.presentViewController(alertController, animated: true, completion: nil)
}
The UIAlertController have the function dismissViewControllerAnimated(flag: Bool, completion: (() -> Void)?) that according to Apple:
Dismisses the view controller that was presented modally by the view controller.
Then what you need to do is to keep a reference to the UIAlertController as a property in your UIViewController and then dismiss it as you like, something like this:
// instance of the UIAlertController to dismiss later
var alertController: UIAlertController!
func sendLoading() {
self.alertController = UIAlertController(title: "Loading...", message:
"", preferredStyle: UIAlertControllerStyle.Alert)
self.presentViewController(alertController, animated: true, completion: nil)
}
let myUrl = NSURL(string: "http://www.test.org/ios.html")
let request = NSMutableURLRequest(URL: myUrl!)
request.HTTPMethod = "POST"
let task = NSURLSession.sharedSession().dataTaskWithRequest(request) {
data, response, error in
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0)) {
let responseString = NSString(data: data!, encoding: NSUTF8StringEncoding)
if error != nil {
print("Error: \(error)")
}
dispatch_async(dispatch_get_main_queue()) {
self.testLabel.text = "\(responseString!)"
// dismiss sendLoading() UIAlert
self.alertController.dismissViewControllerAnimated(true, completion: nil)
}
}
}
task.resume()
self.sendLoading()
I hope this help you.