Milan Manwar
Milan Manwar

Reputation: 374

Resumable multipart file uploads using AFNetworking in Objective - C

I want to develop an app in which I may need to support resumable file upload. Is there any way to support resumable file upload.Please note that I may queue up file uploads also.

I'm using AFNetworking. Server: IIS.

If possible, please provide a robust solution to it. I'm open for both (server-client side) solutions.

Upvotes: 0

Views: 779

Answers (1)

Luis Miguel Sierra
Luis Miguel Sierra

Reputation: 734

For resumable uploads magic must go on server-side. The servers I've use for developing this uploads were using tusd library https://github.com/tus/tusd

I'm sorry but I can't help you much more on server side.

On iOS you have to implement just three HTTP Requests

  1. A HTTP request to generate a file identifier. You should retrieve the file's identifier and associate it to your file (In core data for example).

  2. A HTTP GET request passing the file's identifier to find the file's offset (The last byte of the file received on server).

  3. A HTTP POST request to upload the file. If you are handling with large files, you must use a NSInputStream in order to not allocating memory.

      func uploadFileStream(file: MyFileClass, fileStream: NSInputStream){
    
        self.initialOffset = Double(file.offset)
        self.currentFile = file
        self.fileStream = fileStream 
    
        let url = NSURL(string: self.file.url)!
        var error: NSError?
    
        let request = NSMutableURLRequest(URL: url, cachePolicy: NSURLRequestCachePolicy.ReloadIgnoringLocalCacheData, timeoutInterval: 10.0)
    
        request.HTTPMethod = "POST"
        request.addValue(file.identifier, forHTTPHeaderField: Constants.HEADER_FILE_IDENTIFIER)
        request.addValue(Constants.CONTENT_TYPE_DEFAULT,  forHTTPHeaderField: Constants.HEADER_FILE_CONTENT_TYPE)
    
        var task = session.uploadTaskWithStreamedRequest(request)
    
        fileStream.open()
    
        currentTask = task
        task.resume()
    }
    

Also you have to implement NSURLSessionTaskDelegate to provide the streamRequest a Body:

    func URLSession(session: NSURLSession, task: NSURLSessionTask, needNewBodyStream completionHandler: (NSInputStream!) -> Void) {
        if let stream = self.fileStream{
            // set the current offset as the starting point of the stream
            stream.setProperty(Int(self.currentFile.offset), forKey: NSStreamFileCurrentOffsetKey)
            // Set the stream as the request body
            completionHandler(stream)
        }
    }

        func URLSession(session: NSURLSession, task: NSURLSessionTask, didSendBodyData bytesSent: Int64, totalBytesSent: Int64, totalBytesExpectedToSend: Int64) {

            // Save current offset in database. This offset only indicates the amount of bytes sent, not the received in server.  
            let currentOffset = Double(self.initialOffset + Double(totalBytesSent))
            FilesDAO.saveOffset(fromFile: self.currentFile, offset: currentOffset)

    }

func URLSession(session: NSURLSession, task: NSURLSessionTask, didCompleteWithError error: NSError?){

    if let err = error{

       // An error ocurred. You can retry the process of uploading

    }else{

       // The file was uploaded successfully

    }
}

Basically it is all you'll need on your client. Then you will have to set different headers or request body depending on the server implementation

Upvotes: 1

Related Questions