首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >iOS 10 -无需互联网即可保存图片- Swift 3.0和Xcode8.2

iOS 10 -无需互联网即可保存图片- Swift 3.0和Xcode8.2
EN

Stack Overflow用户
提问于 2017-03-21 03:45:06
回答 2查看 341关注 0票数 0

我正在做一个应用程序(使用Xcode8.2.1,iOS 10和swift 3.0),用户可以制作热照片和普通照片(RGB)。然后,他可以将它们上传到亚马逊s3。但是,如果用户在上传一张或多张图片时没有互联网,会发生什么呢?我该如何解决这个问题?我只能想到两个解决方案,使用coredata或sqlite,您建议我使用哪一个?

另一方面,当我检测到手机没有互联网连接时。

EN

回答 2

Stack Overflow用户

发布于 2017-03-21 06:48:43

或者,您也可以使用后台URLSession,一旦建立了互联网连接,它就会上传文件。它还有一个好处,即使用户当时是在线的,如果他们在上传过程中离开了你的应用程序,即使他们离开了你的应用程序,上传也会继续(不过,如果他们通过双击主页按钮手动关闭应用程序,就不会这样了)。

不幸的是,后台会话处理起来必然要麻烦得多。关键的问题是,当上传完成时,你的应用程序可能不会运行。在这种情况下,当应用程序重新启动时,很明显,在创建上传时传递的任何闭包都已经消失得很久了。这意味着完成处理模式不适用于后台会话。你必须使用URLSession API的基于委托的呈现,你必须在你的应用委托中实现额外的方法,等等。但是如果你搜索"background URLSession tutorial swift 3",你会发现一些例子。

在评论中,你提到你正在使用Alamofire。这在创建GET/POST请求时很棒,但在处理后台请求时也不会更好(可能更糟)。

  1. 你必须创建一个后台SessionManager
  2. 您无法从内存上载文件(因为您的应用程序可能已不存在),因此您必须从文件上载。

例如,在Swift 3中:

代码语言:javascript
复制
//  BackgroundSession.swift

import Foundation
import Alamofire
import MobileCoreServices
import UserNotifications

class BackgroundSession {
    private var sessionManager: SessionManager!

    var completionHandler: (() -> Void)?

    static private(set) var shared = BackgroundSession()

    var responseBodies = [Int: Data]()

    private init() {
        let configuration = URLSessionConfiguration.background(withIdentifier: "com.example.app.background")
        sessionManager = Alamofire.SessionManager(configuration: configuration)

        // for giggles and grins, let's monitor uploads (while app is active, at least)

        sessionManager.delegate.taskDidSendBodyData = { session, task, bytesSent, totalBytesSent, totalBytesExpectedToSend in
            print("\(totalBytesSent) of \(totalBytesExpectedToSend)")
        }

        // if app delegate captured completion handler, let's call it here

        sessionManager.delegate.sessionDidFinishEventsForBackgroundURLSession = { [weak self] session in
            self?.completionHandler?()
            self?.completionHandler = nil
        }

        // we probably want to capture body of response from server

        sessionManager.delegate.dataTaskDidReceiveData = { [weak self] session, task, data in
            if self?.responseBodies[task.taskIdentifier] == nil {
                self?.responseBodies[task.taskIdentifier] = Data()
            }
            self?.responseBodies[task.taskIdentifier]?.append(data)
        }

        // what to do when task completes
        //
        // I'm posting `UNNotificationRequest` (in case app wasn't running when upload finished),
        // but you'd probably want to post NotificationCenter so your view controller could update
        // itself accordingly.

        sessionManager.delegate.taskDidComplete = { [weak self] session, task, error in
            var title: String

            if error != nil {
                print("error = \(error!)")
                title = error!.localizedDescription
            } else {
                // parse your self?.responseBodies[task.taskIdentifier] to make sure request succeeded
                title = ...
            }
            self?.responseBodies[task.taskIdentifier] = nil

            let content = UNMutableNotificationContent()
            content.title = title
            content.body = "Whoo, hoo!"
            let trigger = UNTimeIntervalNotificationTrigger(timeInterval: 1, repeats: false)
            let notification = UNNotificationRequest(identifier: "timer", content: content, trigger: trigger)
            UNUserNotificationCenter.current().add(notification)
        }
    }

    @discardableResult func upload(_ data: Data, name: String, filename: String, to url: URL) throws -> UploadRequest {
        // create multipart body

        let multipart = MultipartFormData()
        multipart.append(data, withName: name, fileName: filename, mimeType: URL(fileURLWithPath: filename).mimeType)
        let fileURL = try FileManager.default.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: false)
            .appendingPathComponent(temporaryFileName())
        try multipart.writeEncodedData(to: fileURL)

        // create request

        var request = try! URLRequest(url: url, method: .post)
        request.setValue("multipart/form-data; boundary=\(multipart.boundary)", forHTTPHeaderField: "Content-Type")

        // initiate upload

        let uploadRequest = sessionManager.upload(fileURL, with: request)
        uploadRequest.resume()
        return uploadRequest
    }

    private func temporaryFileName() -> String {
        return UUID().uuidString
    }

}

extension URL {

    /// Determine mime type on the basis of extension of a file.
    ///
    /// This requires MobileCoreServices framework.
    ///
    /// - parameter url:  The file `URL` of the local file for which we are going to determine the mime type.
    ///
    /// - returns:        Returns the mime type if successful. Returns application/octet-stream if unable to determine mime type.

    var mimeType: String {
        if let uti = UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension, pathExtension as NSString, nil)?.takeRetainedValue() {
            if let mimetype = UTTypeCopyPreferredTagWithClass(uti, kUTTagClassMIMEType)?.takeRetainedValue() {
                return mimetype as String
            }
        }
        return "application/octet-stream";
    }

}

而且,你还必须告诉你的应用程序代理,注意它是否被后台会话处理唤醒,如果是,则捕获完成处理程序:

代码语言:javascript
复制
func application(_ application: UIApplication, handleEventsForBackgroundURLSession identifier: String, completionHandler: @escaping () -> Void) {
    BackgroundSession.shared.completionHandler = completionHandler
}
票数 1
EN

Stack Overflow用户

发布于 2017-03-22 05:47:04

但是,如果您确实需要保存图像并在以后发送它,您可以使用CoreData保存它,或者使用NSKeyedArchiver将其作为序列化对象保存在documents文件夹中,对于只有一张或几张图像,这可能会更简单一些。两者都有各自的优点和缺点。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/42912645

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档