Sqlite iOS 10-不使用internet保存图片-Swift 3.0和Xcode 8.2
我正在使用Xcode 8.2.1、iOS 10和swift 3.0制作一个应用程序,用户可以在其中制作RGB的热像照片和普通照片。然后他可以将它们上传到AmazonS3。 但是,如果用户在上传一张或多张图像时没有互联网,会发生什么呢?我该如何解决这个问题? 我只能想到两种解决方案,coredata或sqlite,您建议我哪一种Sqlite iOS 10-不使用internet保存图片-Swift 3.0和Xcode 8.2,sqlite,core-data,swift3,ios10,save-image,Sqlite,Core Data,Swift3,Ios10,Save Image,我正在使用Xcode 8.2.1、iOS 10和swift 3.0制作一个应用程序,用户可以在其中制作RGB的热像照片和普通照片。然后他可以将它们上传到AmazonS3。 但是,如果用户在上传一张或多张图像时没有互联网,会发生什么呢?我该如何解决这个问题? 我只能想到两种解决方案,coredata或sqlite,您建议我哪一种 另一方面,当我检测到手机没有互联网连接时。您也可以使用后台URLSession,一旦建立互联网连接,它将上载文件。它还有一个好处,即即使用户当时在线,如果他们在上传过程中
另一方面,当我检测到手机没有互联网连接时。您也可以使用后台URLSession,一旦建立互联网连接,它将上载文件。它还有一个好处,即即使用户当时在线,如果他们在上传过程中离开你的应用程序,即使他们离开你的应用程序,它也会继续,而不是如果他们通过双击home按钮手动关闭应用程序 不幸的是,处理后台会话必然要麻烦得多。关键问题是,上传完成后,您的应用程序可能无法运行。在这种情况下,当应用程序重新启动时,显然创建上传时通过的任何闭包都早已消失。这意味着完成处理程序模式不适用于后台会话。你必须使用基于委托的URLSession API格式副本,你必须在你的应用程序委托中实现其他方法,等等。但是如果你用谷歌搜索背景URLSession教程swift 3,你会发现一些例子 在评论中,您提到您正在使用Alamofire。这在创建GET/POST请求方面非常好,但在处理后台请求时没有更好,甚至更糟 您必须创建一个后台会话管理器 您无法从内存上载文件,因为您的应用程序可能已丢失,因此您必须从文件上载。这意味着,如果您要创建一个复杂的POST请求(JSON或多部分/表单数据或其他),那么您必须创建它,将其保存到一个文件中,然后上传该文件 您不能依赖上载的完成处理程序,因此您必须在taskDidComplete、dataTaskDidReceiveData、SessiondFinisheVentsforBackgroundUrlSession等会话管理器委托的闭包中完成所有处理 例如,在Swift 3中:
// 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";
}
}
此外,您还必须告诉您的应用程序代理密切注意它是否被唤醒进行后台会话处理,并捕获完成处理程序,如果是:
func application(_ application: UIApplication, handleEventsForBackgroundURLSession identifier: String, completionHandler: @escaping () -> Void) {
BackgroundSession.shared.completionHandler = completionHandler
}
不幸的是,如上所述,这是对实际实现的粗略简化,因为您可能不想仅仅依赖UNUserNotificationCenter,而是希望相应地更新您自己的UI,因此,您可能正在处理NotificationCenter消息或跟踪回调闭包数组,这些回调闭包数组将通过任务标识符等进行绑定。通常在这种情况下,用户应该通过某种类型的错误消息通知上传失败,并要求稍后再次执行。但是,如果确实需要保存图像并在以后发送,则可以使用CoreData保存图像,或者使用NSKeyedArchiver将其作为序列化对象保存在documents文件夹中,这对于一个或几个图像来说可能更简单。两者各有利弊。这是个好主意:!我没有想过。我想告诉您,我正在使用RESTAPI执行GET和POST,并且我正在使用Almofire框架和回调。我现在的问题是,如果我用Almofire调用callbacks,它的结果是否与URLSession相同?但是如果用户在没有互联网的情况下拍了几张照片,这些照片都上传了吗?