atom-22
atom-22

Reputation: 199

Alamofire upload Completion block works right on iOS 9 & IOS 11 but wrong on iOS 10

I want Alamofire to upload data to the server and depends on the result:

  1. hide progress alert, dismiss current view controller, show congratulations alert
  2. hide progress alert, show error alert

My code works fine on iOS 9 and 11, but on iOS 10 on success case only hides progress alert. Users are confused and submit the form again and again

Alamofire.upload(multipartFormData: { MultipartFormData in
MultipartFormData.append((self.model.name?.data(using: String.Encoding.utf8)!)!, withName: "Form[name]")
MultipartFormData.append((self.model.category?.description.data(using: String.Encoding.utf8)!)!, withName: "Form[category]")
    if (self.filePreview.count>0) {
        for (index,preview) in self.filePreview.enumerated() {
                if preview != nil 
                    let data = UIImageJPEGRepresentation((preview?.getImage())!, 80)
                    MultipartFormData.append(data!, withName: "Form[files]["+String(describing:index)+"]", fileName: "attachment"+String(describing: index)+".JPG", mimeType: preview!.getMime())
                }
            }
        }
        debugPrint(MultipartFormData)
        }, to: url, encodingCompletion: { (result) in
            switch result {
            case .success( _, _, _):
                progressAlert.dismiss(animated: true, completion: nil)
                self.dismiss(animated: true, completion: nil)
                let doneAlert = UIAlertController(title: "Success", message: "Your message was sent", preferredStyle: .alert)
                let donedOk = UIAlertAction(title: "OK", style: .default, handler: nil)
                doneAlert.addAction(donedOk)
                self.present(doneAlert, animated: true, completion: nil)
                break
            case .failure( _):
                progressAlert.dismiss(animated: true, completion: nil)
                let doneAlert = UIAlertController(title: "Failed", message: "Your message was not sent", preferredStyle: .alert)
                let donedOk = UIAlertAction(title: "OK", style: .default, handler: nil)
                doneAlert.addAction(donedOk)
                self.present(doneAlert, animated: true, completion: nil)
                break
            }
        })

Upvotes: 1

Views: 184

Answers (3)

Boris Ch.F
Boris Ch.F

Reputation: 156

The order should be.

  1. dismiss progress.
  2. Show alert saying that everything is fine. (this will obscure the interface so theres no possibility touch anything behind ) When on step 2 tap over ok.
  3. dismiss the upload controller.

Just to update code by rocky :

There´s no need to switch to MainQueue, Math Thompson on the resulting closure output to DispatchQueue.main.async.

So From my point of view interactions should be like :

switch result {
            case .success( _, _, _):
             //1
                progressAlert.dismiss(animated: true, completion: nil)
            //2
        let doneAlertController = UIAlertController(title: "Success", message: "Your message was sent", preferredStyle: .alert)
        let donedOk = UIAlertAction(title: "OK", style: .default) { (action) in
         //3   
         self.dismiss(animated: true, completion: nil)
        }

        doneAlertController.addAction(donedOk)
        self.present(doneAlertController, animated: true, completion: nil)
                break

. . . . . .

Upvotes: 0

atom-22
atom-22

Reputation: 199

Working with completition handlers and using UIApplication.shared.keyWindow?.rootViewController to find current top ViewController solved problem. Progress alert hides, current view controller dismisses, and success alert appears. Code:

progressAlert.dismiss(animated: true) {
    let doneAlert = UIAlertController(title: "Отправлено", message: "Your message was sent", preferredStyle: .alert)
    let donedOk = UIAlertAction(title: "Success", style: .default, handler: nil)
    doneAlert.addAction(donedOk)
    self.dismiss(animated: true) {
        let presentingVC = UIApplication.shared.keyWindow?.rootViewController
        presentingVC?.present(doneAlert, animated: true, completion: nil)
    }
}

Upvotes: 1

Rocky
Rocky

Reputation: 3235

Issue with presenting a UIAlertController on the Controller whose view is not in the window hierarchy, firstly you are dismissing the controller & presenting UIAlertController on that dismissed controller.

You have to take a reference of controller on which the current controller is presenting, then after dismissing of current controller present UIAlertController on that previous one.

Update user interface on Main dispatch queue.

DispatchQueue.main.async {
    let controller = self.presentingViewController
    self.dismiss(animated: true) {
         let doneAlert = UIAlertController(title: "Success", message: "Your message was sent", preferredStyle: .alert)
         let donedOk = UIAlertAction(title: "OK", style: .default, handler: nil)
         doneAlert.addAction(donedOk)
         controller?.present(doneAlert, animated: true, completion: nil)
    }
}

Upvotes: 0

Related Questions