Search code examples
iosswiftalamofirensnotificationcenter

Notification-Observer pattern for file upload progress works only when the file is large - swift?


I have a single view application that uploads images to a remote server. When the user submits the upload, I use a second view controller that displays as a custom popup and shows the file upload progress. When the upload is complete, the custom popup unwinds to the first viewController. I am using the notification-obersever pattern to communicate between the two viewControllers.

My problem is the following: When I upload large files, the upload progress bar can be observed and the custom popup unwinds after the upload is complete. When I am uploading a small file, the upload time is very faast, even though the file is successfully uploaded, the upload progress is not observed and the custom popup does not unwind (see code below).

I'm not sure that I have set up the notification-observer pattern up correctly?

FIRST VIEWCONTROLLER:

Alamofire.upload(
        multipartFormData: { multipartFormData in
            for(key, value) in sendParamters{
                multipartFormData.append((value.data(using: .utf8)!), withName: key)
            }

            for fileURL in arrayURLToUpload{
                print("fileURL: \(fileURL)")
                multipartFormData.append(fileURL, withName: "file[]")
            }
        },
            to: UPLOAD_URL,
            encodingCompletion: { encodingResult in
                switch encodingResult {
                case .success(let upload, _, _):

                    /**TRACK PROGRESS OF UPLOAD**/
                    upload.uploadProgress { progress in
                        print("ECNTERFILENAME: \(progress.fractionCompleted)")

                        let progress = progress.fractionCompleted

                        // NOTIFICATION - UPLOAD PROGRESS
                        NotificationCenter.default.post(name: notifcationName, object: nil, userInfo: ["progress": progress])
                    }
                    /***/


                    // 'responseJSON' FIRES WHEN UPLOAD IS COMPLETE
                    // IT ALSO TO FIRES WHEN THE IS INTERNET CONNECTIVITY ISSUES
                    upload.responseJSON { response in


                        // NOTIFICATION UPLOAD COMPLETE
                        NotificationCenter.default.post(name: uploadFinishName, object: nil, userInfo: ["response": response])
                    }


                case .failure(let encodingError):
                    print("UPLOAD ERROR")
                    print(encodingError)
                }
        }
    )

SECOND VIEWCONTROLLER:

override func viewDidLoad() {
    super.viewDidLoad()

    self.createUploadObserver()
    self.createUploadFinishObserver()

    if txtLabelOutlet == nil{ // WHEN IMAGE('tickok') HAS REPLACED 'txtLabelOutlet'
        reformTxtLabel()
    }


    self.infoLabelOutlet.textColor = UIColor.black // CAN BE RED WHEN NETWORK CONNECTION IS LOST
    self.progressOutlet.progress = 0   
}



func createUploadObserver(){
    print("createUploadObserver ..")
    NotificationCenter.default.addObserver(forName: notifcationName, object: nil, queue: OperationQueue.main) { (notification) in

        guard
            var arrayN = notification.userInfo as? [String:Double],
            let num = arrayN["progress"] else{
                print("no valid data")
                return
        }
        // UPDATE PROGRESS BAR
        let progress = Float.init(num)
        self.progressOutlet.progress = progress

        // UPDATE LABEL
        let percent = Int(progress*100)
        print("percent: \(percent)")


        if let progressOut = self.txtLabelOutlet{
            print("OUTLET EXISTS!")
            progressOut.text = "\(percent)%"
        }else{
            print("OUTLET DOES NOT EXIST")
        }
    }
}




func createUploadFinishObserver(){
    print("createUploadFinishObserver ..")

    NotificationCenter.default.addObserver(forName: uploadFinishName, object: nil, queue: OperationQueue.main) { (notification) in

        print("notification.userInfo: \(notification.userInfo)")

        guard let response = notification.userInfo as? [String: DataResponse<Any>] else{
            print("Error completion response")
            return
        }

        guard
            let respObj = response["response"] as? DataResponse<Any>,
            let result = respObj.result as? Result<Any> else{return}


        if let value  = result.value{
            print("value: \(value)")
        }

        if result.description == "SUCCESS"{
            // UPLOAD COMPLETE
            // SHOW VIDEO CAPTURE
            print("upload success")


            if let progressOut = self.txtLabelOutlet{
                print("OUTLET EXISTS - REMOVE FROM SUPERVIEW")
                progressOut.removeFromSuperview()
            }else{
                print("OUTLET DOES NOT EXIST to remove from superview")
            }

            // ADD GREEN TICK IMAGE TO SHOW UPLOAD SUCCESS PROGRAMTICALLY
            let image = UIImage.init(named: "tickok")
            self.showCompleteTickImage(image: image!, completion: {

                // DELAY EXECUTION OF DIMISS POPUP BY 2 SECONDS
                DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
                    print("DISMISS PROGRESS POPUP")
                    // DISMISS POUP AND SHOW IMAGE CAPTURE AGAIN
                    self.performSegue(withIdentifier: "inwindme2", sender: self)

                }
            })


        }else{
            // HANDLE UPLOAD FAIL
            print("upload fail")
            self.infoLabelOutlet.text = "Network Connection Lost"
            self.infoLabelOutlet.textColor = UIColor.red
        }
    }
}

Solution

  • May be swap

    self.createUploadFinishObserver()
    self.createUploadObserver()
    

    As it seems that the popupVC when uploading a small file hadn't been yet registered , so the finish post occurs before the observe , also you can start the upload in the completion of the present of that popup ,

    self.present(popup,animated:true) {
      // start upload
    }
    

    If segue

    self.performSegue(///// 
    DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
      // start upload 
    }
    

    The notificationCenter to work , your app logic must be 100% sure that the post occurs after the observe