我正在做一个应用程序(使用Xcode8.2.1,iOS 10和swift 3.0),用户可以制作热照片和普通照片(RGB)。然后,他可以将它们上传到亚马逊s3。但是,如果用户在上传一张或多张图片时没有互联网,会发生什么呢?我该如何解决这个问题?我只能想到两个解决方案,使用coredata或sqlite,您建议我使用哪一个?
另一方面,当我检测到手机没有互联网连接时。
发布于 2017-03-21 06:48:43
或者,您也可以使用后台URLSession,一旦建立了互联网连接,它就会上传文件。它还有一个好处,即使用户当时是在线的,如果他们在上传过程中离开了你的应用程序,即使他们离开了你的应用程序,上传也会继续(不过,如果他们通过双击主页按钮手动关闭应用程序,就不会这样了)。
不幸的是,后台会话处理起来必然要麻烦得多。关键的问题是,当上传完成时,你的应用程序可能不会运行。在这种情况下,当应用程序重新启动时,很明显,在创建上传时传递的任何闭包都已经消失得很久了。这意味着完成处理模式不适用于后台会话。你必须使用URLSession API的基于委托的呈现,你必须在你的应用委托中实现额外的方法,等等。但是如果你搜索"background URLSession tutorial swift 3",你会发现一些例子。
在评论中,你提到你正在使用Alamofire。这在创建GET/POST请求时很棒,但在处理后台请求时也不会更好(可能更糟)。
SessionManager。例如,在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
}发布于 2017-03-22 05:47:04
但是,如果您确实需要保存图像并在以后发送它,您可以使用CoreData保存它,或者使用NSKeyedArchiver将其作为序列化对象保存在documents文件夹中,对于只有一张或几张图像,这可能会更简单一些。两者都有各自的优点和缺点。
https://stackoverflow.com/questions/42912645
复制相似问题