当前位置: 首页 > 面试题库 >

使用单个NSURLSession uploadTaskWithRequest在后台上传多张图片

汤承德
2023-03-14
问题内容

我想使用一种uploadTaskWithRequest方法在后台上传多张图像。在尝试以下代码返回时,后台会话不支持从NSData上载任务…请如何实现此目的

func createRequest (param : NSDictionary ,imagearray :NSMutableArray, strURL : String) -> NSURLRequest {

    let boundary = generateBoundaryString()

    let url = NSURL(string: strURL)
    let request = NSMutableURLRequest(URL: url!)

    request.setValue("multipart/form-data; boundary=\(boundary)", forHTTPHeaderField: "Content-Type")
    request.HTTPMethod = "POST"
    request.HTTPBody = createBodyWithParameters(param, image_array:imagearray,boundary: boundary);

    return request
}

   func createBodyWithParameters(parameters: NSDictionary,image_array:NSMutableArray,boundary: String) -> NSData {
 let body = NSMutableData()         
for (key, value) in parameters {
      if(value is String || value is NSString){
            body.appendString("--\(boundary)\r\n")
            body.appendString("Content-Disposition: form-data; name=\"\(key)\"\r\n\r\n")
            body.appendString("\(value)\r\n")
        }
    }
    var i = 0;
    for image in image_array {
        let filename = "image\(i).jpg"
        let data = UIImagePNGRepresentation(image as! UIImage);
        let mimetype = "image/png"
        body.appendString("--\(boundary)\r\n")
        body.appendString("Content-Disposition: form-data; name=\"\(self.filePathKey)\"; filename=\"\(filename)\"\r\n")
        body.appendString("Content-Type: \(mimetype)\r\n\r\n")
        body.appendData(data!)
        body.appendString("\r\n")
        i += 1;
    }

    body.appendString("--\(boundary)--\r\n")
    //        NSLog("data %@",NSString(data: body, encoding: NSUTF8StringEncoding)!);
    return body
}

func postrequestwithformdata(requesturl:String,postparams:NSDictionary,postformadata:NSMutableArray,requestId:Int)  
{

    self.requestid = requestId;
    let requestformdata = self.createRequest(postparams, imagearray: postformadata, strURL: requesturl);
    let configuration = NSURLSessionConfiguration.backgroundSessionConfigurationWithIdentifier(Contants.identifier)
    let session: NSURLSession = NSURLSession(configuration:configuration, delegate: self, delegateQueue: NSOperationQueue.mainQueue());
    let task: NSURLSessionUploadTask = session.uploadTaskWithRequest(requestformdata, fromData: requestformdata.HTTPBody!);
    task.resume();

}

问题答案:

要在后台会话中上载,必须首先将数据保存到文件中。

  1. 使用writeToFile:options:将数据保存到文件中。
  2. 调用NSURLSession uploadTaskWithRequest:fromFile:创建任务。请注意,请求中不得包含数据,HTTPBody否则上传将失败。
  3. 在URLSession:didCompleteWithError:委托方法中处理完成。

您可能还需要处理在后台运行应用程序时完成的html" target="_blank">上传。

  1. 在AppDelegate中实现application:handleEventsForBackgroundURLSession:completionHandler。
  2. 使用提供的标识符创建一个NSURLSession。
  3. 按照通常的上载方式响应委托方法(例如,处理URLSession:didCompleteWithError:中的响应)
  4. 完成处理事件后,调用URLSessionDidFinishEventsForBackgroundURLSession。

为了使其更易于管理,请NSURLSession为每个上传任务创建一个,每个任务都有一个唯一的标识符。

有关实现的详细信息,请参阅《URL会话编程指南》。

AppDelegate示例:

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate, NSURLSessionDelegate, NSURLSessionTaskDelegate {

    var window: UIWindow?

    typealias CompletionHandler = () -> Void

    var completionHandlers = [String: CompletionHandler]()

    var sessions = [String: NSURLSession]()


    func upload(request: NSURLRequest, data: NSData)
    {
        // Create a unique identifier for the session.
        let sessionIdentifier = NSUUID().UUIDString

        let directoryURL = NSFileManager.defaultManager().URLsForDirectory(.CachesDirectory, inDomains: .UserDomainMask).first!
        let fileURL = directoryURL.URLByAppendingPathComponent(sessionIdentifier)

        // Write data to cache file.
        data.writeToURL(fileURL, atomically: true);

        let configuration = NSURLSessionConfiguration.backgroundSessionConfigurationWithIdentifier(sessionIdentifier)

        let session: NSURLSession = NSURLSession(
            configuration:configuration,
            delegate: self,
            delegateQueue: NSOperationQueue.mainQueue()
        )

        // Store the session, so that we don't recreate it if app resumes from suspend.
        sessions[sessionIdentifier] = session

        let task = session.uploadTaskWithRequest(request, fromFile: fileURL)

        task.resume()
    }

    // Called when the app becomes active, if an upload completed while the app was in the background.
    func application(application: UIApplication, handleEventsForBackgroundURLSession identifier: String, completionHandler: CompletionHandler) {

        let configuration = NSURLSessionConfiguration.backgroundSessionConfigurationWithIdentifier(identifier)

        if sessions[identifier] == nil {

            let session = NSURLSession(
                configuration: configuration,
                delegate: self,
                delegateQueue: NSOperationQueue.mainQueue()
            )

            sessions[identifier] = session
        }

        completionHandlers[identifier] = completionHandler
    }

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

        // Handle background session completion handlers.
        if let identifier = session.configuration.identifier {

            if let completionHandler = completionHandlers[identifier] {
                completionHandler()
                completionHandlers.removeValueForKey(identifier)
            }

            // Remove session
            sessions.removeValueForKey(identifier)
        }

        // Upload completed.
    }
}

要在单个请求中上载多个图像,必须先将图像编码为multipart / formdata
MIME类型,就像您所做的一样。区别在于,整个MIME消息必须保存到一个文件中,该文件是上载到服务器的文件。

这是显示此方法的示例。它通过将MIME部分直接序列化到文件来工作。您也可以在NSData中构建消息,尽管在处理大文件时可能会遇到内存限制。

func uploadImages(request: NSURLRequest, images: [UIImage]) {

    let uuid = NSUUID().UUIDString
    let boundary = String(count: 24, repeatedValue: "-" as Character) + uuid

    // Open the file
    let directoryURL = NSFileManager.defaultManager().URLsForDirectory(.CachesDirectory, inDomains: .UserDomainMask).first!

    let fileURL = directoryURL.URLByAppendingPathComponent(uuid)
    let filePath = fileURL.path!

    NSFileManager.defaultManager().createFileAtPath(filePath, contents: nil, attributes: nil)

    let file = NSFileHandle(forWritingAtPath: filePath)!


    // Write each image to a MIME part.
    let newline = "\r\n"

    for (i, image) in images.enumerate() {

        let partName = "image-\(i)"
        let partFilename = "\(partName).png"
        let partMimeType = "image/png"
        let partData = UIImagePNGRepresentation(image)

        // Write boundary header
        var header = ""
        header += "--\(boundary)" + newline
        header += "Content-Disposition: form-data; name=\"\(partName)\"; filename=\"\(partFilename)\"" + newline
        header += "Content-Type: \(partMimeType)" + newline
        header += newline

        let headerData = header.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)

        print("")
        print("Writing header #\(i)")
        print(header)

        print("Writing data")
        print("\(partData!.length) Bytes")

        // Write data
        file.writeData(headerData!)
        file.writeData(partData!)
    }

    // Write boundary footer
    var footer = ""
    footer += newline
    footer += "--\(boundary)--" + newline
    footer += newline

    print("")
    print("Writing footer")
    print(footer)

    let footerData = footer.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)
    file.writeData(footerData!)

    file.closeFile()

    // Add the content type for the request to multipart.
    let outputRequest = request.copy() as! NSMutableURLRequest

    let contentType = "multipart/form-data; boundary=\(boundary)"
    outputRequest.setValue(contentType, forHTTPHeaderField: "Content-Type")


    // Start uploading files.
    upload(outputRequest, fileURL: fileURL)
}


 类似资料:
  • 问题内容: 我是在项目中使用代码点火器的新用户,上载多个文件时遇到一个问题,但最后一个仅插入到所有图像“三个图像”字段中。 我的控制器是: 我的观点是: 请帮助如何插入3张图像。 我的资料库 问题答案: HTML: PHP的:

  • 问题内容: 我使用,并将一些图像加载到上。 现在,我需要一次上传所有这些图像。正在使用,我该怎么做? 我浏览了文档,有一个名为的部分。但是,我无法上传中的图像。 *注意:我想以Byte Array 的形式上传图像。我怎样才能做到这一点?* 我到目前为止的代码, 问题答案: 试试这个。

  • 问题内容: 我正在使用以下代码将单个图像上传到服务器: 如何通过编辑此代码在单个参数中上传多张图片? 问题答案: Swift 3 只需在图像上传参数中使用“ []”即可使其成为图像数组。

  • 问题内容: 我在Swift iOS项目中使用Google Firebase。我的应用程序有一部分,用户从设备中选择多张照片进行上传。我正在尝试找到最佳实践,以将他们一次选择的所有照片上传到Firebase Storage。我知道如何上传一张照片。 我浏览了文档,没有看到有关上载多个NSData对象的任何方法,所以我只需要运行for循环并分别上载每个图像? 谢谢!感谢所有反馈。 问题答案: @Fra

  • 问题内容: 我也曾在SO和其他教程中发表过很多文章,但是我没有得到任何最新的官方或其他文章,这些文章不包含使用Volley上传多个图像的弃用代码。我知道Apache HTTP Client删除并在新的android M中相关,因此建议改用下面的方法。 那么,有谁能帮我完成新的不推荐使用的少排球类上载多张图片的工作? 问题答案: 您可以从此处使用volley的最新版本。这是一个非官方的镜像,带有一些

  • 我在SO和其他tuts中看了很多帖子,但我无法得到任何最新的官方或其他帖子,其中不包含任何关于使用排球上传多个图片的不推荐代码。我了解了Apache HTTP客户端删除和新android M中的相关内容,所以更喜欢使用下面的内容。