Ios Swift 3/Xcode 8-缓存读取:无法打开缓存文件;NetworkStorageDB:\u openDBReadConnections:无法打开到数据库的读取连接
我目前正在开发一个iOS应用程序,需要从几个提要中检索一些信息。使用这些数据,我创建了一个表视图来显示它们。不幸的是,有时我会出现以下错误:Ios Swift 3/Xcode 8-缓存读取:无法打开缓存文件;NetworkStorageDB:\u openDBReadConnections:无法打开到数据库的读取连接,ios,uitableview,caching,swift3,nsurlcache,Ios,Uitableview,Caching,Swift3,Nsurlcache,我目前正在开发一个iOS应用程序,需要从几个提要中检索一些信息。使用这些数据,我创建了一个表视图来显示它们。不幸的是,有时我会出现以下错误: NetworkStorageDB:_openDBReadConnections: failed to open read connection to DB CacheRead: unable to open cache files in... 以下是调试控制台中的内容: 2016-10-27 10:59:54.490 tdr-ios-prototype
NetworkStorageDB:_openDBReadConnections: failed to open read connection to DB
CacheRead: unable to open cache files in...
以下是调试控制台中的内容:
2016-10-27 10:59:54.490 tdr-ios-prototype[5216:129128] NetworkStorageDB:_openDBReadConnections: failed to open read connection to DB @ /Users/e-novinfo/Library/Developer/CoreSimulator/Devices/1EE7579E-CEC3-4CBF-BB64-438FCDE1C61A/data/Containers/Data/Application/06427070-79E6-4534-BAFC-7EAFF79460C7/Library/Caches/com.e-novinfo.tdr-ios-prototype/Cache.db. Error=14. Cause=unable to open database file
2016-10-27 10:59:54.491 tdr-ios-prototype[5216:129128] CacheRead: unable to open cache files in /Users/e-novinfo/Library/Developer/CoreSimulator/Devices/1EE7579E-CEC3-4CBF-BB64-438FCDE1C61A/data/Containers/Data/Application/06427070-79E6-4534-BAFC-7EAFF79460C7/Library/Caches/com.e-novinfo.tdr-ios-prototype
基本上,我只是从一个URL解析一个JSON,然后使用我扩展的URLCache
类来检查是否有特定请求的缓存。当有大量数据时,我经常遇到这个问题,比如从YouTube检索视频或从Picasa检索图片时
我以这种方式获取数据:在相关表视图控制器的viewdide
上,调用名为loadMedia
的方法,该方法将使用一个类,例如PicasaWebServices(singleton)。最后一个类将通过URLSession.shared.dataTask
到达JSON。在发出请求之前,我会检查相关请求是否有缓存,如果缓存不是太旧,我会使用它。否则,我会清理缓存。如果没有连接(通过可达性检查),则使用缓存。最后,如果有响应,则将数据放置在表视图控制器中。创建显示时,可以通过URLSession.shared.dataTask
访问其他信息,如我需要的图像(我使用UIImageView
扩展名来实现这一点)
我首先怀疑缓存过载,所以在我的URLCache
扩展中添加了一些检查,但没有解决问题。可能有太多的请求URLSession.shared.dataTask
,我不得不延迟它们,但我不知道该怎么做
只有在使用模拟器运行应用程序时,才会发生此错误。在iPhone 6上,有时,在相同的情况下,我会出现以下错误:
libc++abi.dylib: terminating with uncaught exception of type NSException
当显示Picasa的相册列表时,我试图通过点击一行转到下一个显示相册内容的视图时,经常会发生这种情况
任何帮助都将不胜感激!非常感谢
例如,以下是我的Picasa Web服务:
class PicasaWebServices {
//MARK: Properties
/**********************/
/***** PROPERTIES *****/
/**********************/
static let sharedInstance = PicasaWebServices()
fileprivate var googleApiKey: String = "..."
fileprivate var picasaUsername: String = "..."
fileprivate var reachability: Reachability?
/****************************************/
/****************************************/
/****************/
/***** INIT *****/
/****************/
fileprivate init() {
self.reachability = Reachability()!
//END init
}
/****************************************/
/****************************************/
/*****************************/
/***** GET PICASA ALBUMS *****/
/*****************************/
func getPicasaAlbums( _ completionHandler:@escaping ( Array< Dictionary< String, AnyObject > >?, NSError? ) -> Void ) {
let requestURL = "http://picasaweb.google.com/data/feed/api/user/\( picasaUsername )?kind=album&access=public&prettyprint=true&thumbsize=320c&imgmax=640&fields=entry(id,title,link(@href),gphoto:id,media:group(media:thumbnail,media:description))&alt=json"
let url = URL( string: requestURL )!
let request = NSMutableURLRequest( url: url )
URLCache().checkIfCacheForRequest( request )
URLSession.shared.dataTask( with: request as URLRequest ) { data, response, error in
if error != nil {
completionHandler( nil, error as NSError? )
return;
}
var jsonError: NSError?
var jsonResult: AnyObject?
do {
jsonResult = try JSONSerialization.jsonObject( with: data!, options: [] ) as AnyObject
} catch let error as NSError {
jsonError = error
jsonResult = nil
} catch {
fatalError()
}
var albums: Array< Dictionary< String, AnyObject > > = []
let jsonResultFeed = jsonResult![ "feed" ] as! [ String: AnyObject ]
if let items = jsonResultFeed[ "entry" ] as? [ [ String: AnyObject ] ] {
for item in items {
albums.append( item )
//END for item in items
}
//END if let items = jsonResultFeed[ "entry" ] as? [ [ String: AnyObject ] ]
}
completionHandler( albums, jsonError );
//END let dataTask = urlSession.dataTaskWithURL( url, completionHandler: { ( data, response, error ) -> Void in
}.resume()
//END getPicasaAlbums
}
/****************************************/
/****************************************/
/************************************/
/***** GET PICASA ALBUM CONTENT *****/
/************************************/
func getPicasaAlbumContent( _ requestURL: String, completionHandler:@escaping ( Array<Dictionary<String, AnyObject>>?, NSError? ) -> Void ) {
let url = URL( string: requestURL )!
let request = NSMutableURLRequest( url: url )
URLCache().checkIfCacheForRequest( request )
URLSession.shared.dataTask( with: request as URLRequest ) { data, response, error in
if error != nil {
completionHandler( nil, error as NSError? )
return;
}
var jsonError: NSError?
var jsonResult: AnyObject?
do {
jsonResult = try JSONSerialization.jsonObject( with: data!, options: [] ) as AnyObject
} catch let error as NSError {
jsonError = error
jsonResult = nil
} catch {
fatalError()
}
var photos: Array< Dictionary< String, AnyObject > > = []
let jsonResultFeed = jsonResult![ "feed" ] as! [ String: AnyObject ]
if let items = jsonResultFeed[ "entry" ] as? [ [ String: AnyObject ] ] {
for item in items {
photos.append( item )
//END for item in items
}
//END if let items = jsonResultFeed[ "entry" ] as? [ [ String: AnyObject ] ]
}
completionHandler( photos, jsonError );
//END let dataTask = urlSession.dataTaskWithURL( url, completionHandler: { ( data, response, error ) -> Void in
}.resume()
//END getPicasaAlbumContent
}
//END PicasaWebServices
}
其中我调用数据(TableViewController):
更新1:
因此,经过多次检查,问题似乎来自使用URLCache扩展时的UIImageView扩展。当有许多图像要加载时,检查缓存的状态似乎有问题,并引发CacheRead:cannot open cache files in…
错误。对于TableViewController,图像通过cellForRowAt
功能加载。你知道我怎么处理吗
/*******************/
/***** IMPORTS *****/
/*******************/
import UIKit
/****************************************/
/****************************************/
/**********************/
/***** ERROR TYPE *****/
/**********************/
enum UrlCacheExtensionError: Error {
case empty
case dateError
}
/****************************************/
/****************************************/
/*****************/
/***** CLASS *****/
/*****************/
extension URLCache {
/**********************************/
/***** GET THE REQUEST'S DATE *****/
/**********************************/
/*
* @param Dictionary headers request's headers
* @return NSDate
*/
public func getRequestDate( _ headers: Dictionary< String, AnyObject > ) throws -> Date {
var output = Date()
guard !headers.isEmpty else {
throw UrlCacheExtensionError.empty
}
if let theDate = headers[ "Date" ] as? String {
let formatedDate = Date().formateStringToDate( theDate, format: "E, dd MMM yyyy HH:mm:ss zzz", localIdentifier: "en_US" )
print( formatedDate )
output = formatedDate
}
return output
//END getRequestDate
}
/****************************************/
/****************************************/
/*************************************/
/***** GET THE REQUEST'S HEADERS *****/
/*************************************/
/*
* @param NSMutableURLRequest request the request
* @return Dictionary
*/
public func getRequestHeaders( _ request: NSMutableURLRequest ) throws -> Dictionary<NSObject, AnyObject> {
var headers: Dictionary<NSObject, AnyObject>
let cacheResponse = URLCache.shared.cachedResponse( for: request as URLRequest )
if let response = cacheResponse?.response as? HTTPURLResponse {
headers = response.allHeaderFields as Dictionary<NSObject, AnyObject>
} else {
throw UrlCacheExtensionError.empty
}
return headers
//END getRequestHeaders
}
/****************************************/
/****************************************/
/**************************************************/
/***** CHECK IF CACHE IS OLDER THAN ONE VALUE *****/
/**************************************************/
/*
* @param NSDate date the cache date
* @param Int time time to compare
* @return Bool
*/
public func checkIfCacheIsOlder( _ date: Date, time: Int ) throws -> Bool {
guard date == date else {
throw UrlCacheExtensionError.dateError
}
if Date().compareDatesInSeconds( date ) >= time {
return true
} else {
return false
}
//END checkIfCacheIsOlder
}
/****************************************/
/****************************************/
/********************************************************************/
/***** CHECK IF THE CACHE HAS BE CLEANED FOR A SPECIFIC REQUEST *****/
/********************************************************************/
/*
* @param NSMutableURLRequest request the request
* @return Bool
*/
@discardableResult
public func checkIfCacheHasToBeCleanedForRequest( _ request: NSMutableURLRequest ) -> Bool {
let reachability = Reachability()!
if !reachability.isReachable {
return false
} else {
do {
let requestHeaders = try getRequestHeaders( request )
do {
let requestDate = try getRequestDate( requestHeaders as! Dictionary<String, AnyObject> )
do {
let isCacheOlder = try checkIfCacheIsOlder( requestDate, time: 30 )
if isCacheOlder {
//Broken in 9.3 & 9.3.1
//NSURLCache.sharedURLCache().removeCachedResponseForRequest( request )
URLCache.shared.removeAllCachedResponses()
return true
} else {
return false
}
} catch {
return false
}
} catch {
return false
}
} catch {
return false
}
//END else
}
//END checkIfCacheHasToBeCleanedForRequest
}
/****************************************/
/****************************************/
/**************************/
/***** CHECK CAPACITY *****/
/**************************/
public func checkCapacity() -> Void {
if URLCache().currentMemoryUsage >= URLCache().memoryCapacity || URLCache().currentDiskUsage >= URLCache().diskCapacity {
URLCache.shared.removeAllCachedResponses()
}
return
//END checkCapacity
}
/****************************************/
/****************************************/
/*************************************/
/***** CHECK CACHE FOR A REQUEST *****/
/*************************************/
/*
* @param NSMutableURLRequest request the request
* @return Bool
*/
@discardableResult
public func checkIfCacheForRequest( _ request: NSMutableURLRequest ) -> Bool {
let reachability = Reachability()!
if reachability.isReachable {
self.checkCapacity()
let theRequest = self.checkIfCacheHasToBeCleanedForRequest( request )
if theRequest {
request.cachePolicy = .reloadIgnoringCacheData
return false
} else {
request.cachePolicy = .returnCacheDataElseLoad
return true
}
//END if reachability.isReachable
} else {
request.cachePolicy = .returnCacheDataDontLoad
return false
}
//END checkIfCacheForRequest
}
//END NSURLCache
}
extension UIImageView {
/*******************************/
/***** DOWNLOADED FROM URL *****/
/*******************************/
func downloadedFrom( url: URL, contentMode mode: UIViewContentMode = .scaleAspectFit, completionHandler: @escaping( _ image: UIImage?, NSError? ) -> Void ) {
contentMode = mode
let request = NSMutableURLRequest( url: url )
URLCache().checkIfCacheForRequest( request )
URLSession.shared.dataTask( with: request as URLRequest ) { ( data, response, error ) in
//URLSession.shared.dataTask( with: url ) { ( data, response, error ) in
guard
let httpURLResponse = response as? HTTPURLResponse, httpURLResponse.statusCode == 200,
let mimeType = response?.mimeType, mimeType.hasPrefix( "image" ),
let data = data, error == nil,
let image = UIImage( data: data )
else { return }
completionHandler( image as UIImage, nil )
//END URLSession.shared.dataTask
}.resume()
//END downloadedFrom
}
/****************************************/
/****************************************/
/********************************/
/***** DOWNLOADED FROM LINK *****/
/********************************/
func downloadedFrom( link: String, contentMode mode: UIViewContentMode = .scaleAspectFit ) {
guard let url = URL( string: link ) else { return }
self.downloadedFrom( url: url, contentMode: mode, completionHandler: { ( image, error ) -> Void in
if image != nil {
DispatchQueue.main.async( execute: {
self.image = image
} )
//END if posts != nil
}
//END self.downloadedFrom( url: url, contentMode: mode, completionHandler: { ( image, error ) -> Void in
} )
//END downloadedFrom
}
//END UIImageViewExtension
}
func loadMedia() {
PicasaWebServices.sharedInstance.getPicasaAlbums( { ( albums, error ) -> Void in
if albums != nil {
self.media?.removeAll()
self.media = albums
DispatchQueue.main.async( execute: {
self.tableView.reloadData()
} )
//END if albums != nil
}
//END PicasaWebServices.sharedInstance.getPicasaAlbums
} )
}