diff --git a/Framework/Info.plist b/Framework/Info.plist
index e2ecf82..e52b996 100644
--- a/Framework/Info.plist
+++ b/Framework/Info.plist
@@ -15,7 +15,7 @@
CFBundlePackageType
FMWK
CFBundleShortVersionString
- 1.0.3
+ 1.0.4
CFBundleSignature
????
CFBundleVersion
diff --git a/YYWebImage.podspec b/YYWebImage.podspec
index e45217f..22bd9f7 100644
--- a/YYWebImage.podspec
+++ b/YYWebImage.podspec
@@ -1,7 +1,7 @@
Pod::Spec.new do |s|
s.name = 'YYWebImage'
s.summary = 'Asynchronous image loading framework.'
- s.version = '1.0.3'
+ s.version = '1.0.4'
s.license = { :type => 'MIT', :file => 'LICENSE' }
s.authors = { 'ibireme' => 'ibireme@gmail.com' }
s.social_media_url = 'http://blog.ibireme.com'
diff --git a/YYWebImage/Cache/YYDiskCache.h b/YYWebImage/Cache/YYDiskCache.h
index dd193e4..d61c621 100644
--- a/YYWebImage/Cache/YYDiskCache.h
+++ b/YYWebImage/Cache/YYDiskCache.h
@@ -131,10 +131,6 @@ NS_ASSUME_NONNULL_BEGIN
*/
@property NSTimeInterval autoTrimInterval;
-/**
- Set `YES` to enable error logs for debug.
- */
-@property BOOL errorLogsEnabled;
#pragma mark - Initializer
///=============================================================================
diff --git a/YYWebImage/Cache/YYDiskCache.m b/YYWebImage/Cache/YYDiskCache.m
index 735cc5d..77d18c8 100644
--- a/YYWebImage/Cache/YYDiskCache.m
+++ b/YYWebImage/Cache/YYDiskCache.m
@@ -11,7 +11,6 @@
#import "YYDiskCache.h"
#import "YYKVStorage.h"
-#import
#import
#import
#import
@@ -150,18 +149,8 @@ - (NSString *)_filenameForKey:(NSString *)key {
return filename;
}
-- (void)_appWillBeTerminated {
- Lock();
- _kv = nil;
- Unlock();
-}
-
#pragma mark - public
-- (void)dealloc {
- [[NSNotificationCenter defaultCenter] removeObserver:self name:UIApplicationWillTerminateNotification object:nil];
-}
-
- (instancetype)init {
@throw [NSException exceptionWithName:@"YYDiskCache init error" reason:@"YYDiskCache must be initialized with a path. Use 'initWithPath:' or 'initWithPath:inlineThreshold:' instead." userInfo:nil];
return [self initWithPath:@"" inlineThreshold:0];
@@ -204,8 +193,6 @@ - (instancetype)initWithPath:(NSString *)path
[self _trimRecursively];
_YYDiskCacheSetGlobal(self);
-
- [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_appWillBeTerminated) name:UIApplicationWillTerminateNotification object:nil];
return self;
}
@@ -442,17 +429,4 @@ - (NSString *)description {
else return [NSString stringWithFormat:@"<%@: %p> (%@)", self.class, self, _path];
}
-- (BOOL)errorLogsEnabled {
- Lock();
- BOOL enabled = _kv.errorLogsEnabled;
- Unlock();
- return enabled;
-}
-
-- (void)setErrorLogsEnabled:(BOOL)errorLogsEnabled {
- Lock();
- _kv.errorLogsEnabled = errorLogsEnabled;
- Unlock();
-}
-
@end
diff --git a/YYWebImage/Cache/YYKVStorage.m b/YYWebImage/Cache/YYKVStorage.m
index f3587b0..5ea4e27 100644
--- a/YYWebImage/Cache/YYKVStorage.m
+++ b/YYWebImage/Cache/YYKVStorage.m
@@ -19,9 +19,6 @@
#import "sqlite3.h"
#endif
-
-static const NSUInteger kMaxErrorRetryCount = 8;
-static const NSTimeInterval kMinRetryTimeInterval = 2.0;
static const int kPathLengthMax = PATH_MAX - 64;
static NSString *const kDBFileName = @"manifest.sqlite";
static NSString *const kDBShmFileName = @"manifest.sqlite-shm";
@@ -29,19 +26,7 @@
static NSString *const kDataDirectoryName = @"data";
static NSString *const kTrashDirectoryName = @"trash";
-
/*
- File:
- /path/
- /manifest.sqlite
- /manifest.sqlite-shm
- /manifest.sqlite-wal
- /data/
- /e10adc3949ba59abbe56e057f20f883e
- /e10adc3949ba59abbe56e057f20f883e
- /trash/
- /unused_file_or_folder
-
SQL:
create table if not exists manifest (
key text,
@@ -56,22 +41,6 @@ primary key(key)
create index if not exists last_access_time_idx on manifest(last_access_time);
*/
-/// Returns nil in App Extension.
-static UIApplication *_YYSharedApplication() {
- static BOOL isAppExtension = NO;
- static dispatch_once_t onceToken;
- dispatch_once(&onceToken, ^{
- Class cls = NSClassFromString(@"UIApplication");
- if(!cls || ![cls respondsToSelector:@selector(sharedApplication)]) isAppExtension = YES;
- if ([[[NSBundle mainBundle] bundlePath] hasSuffix:@".appex"]) isAppExtension = YES;
- });
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wundeclared-selector"
- return isAppExtension ? nil : [UIApplication performSelector:@selector(sharedApplication)];
-#pragma clang diagnostic pop
-}
-
-
@implementation YYKVStorageItem
@end
@@ -85,40 +54,49 @@ @implementation YYKVStorage {
sqlite3 *_db;
CFMutableDictionaryRef _dbStmtCache;
- NSTimeInterval _dbLastOpenErrorTime;
- NSUInteger _dbOpenErrorCount;
+
+ BOOL _invalidated; ///< If YES, then the db should not open again, all read/write should be ignored.
+ BOOL _dbIsClosing; ///< If YES, then the db is during closing.
}
#pragma mark - db
- (BOOL)_dbOpen {
- if (_db) return YES;
+ BOOL shouldOpen = YES;
+ if (_invalidated) {
+ shouldOpen = NO;
+ } else if (_dbIsClosing) {
+ shouldOpen = NO;
+ } else if (_db){
+ shouldOpen = NO;
+ }
+ if (!shouldOpen) return YES;
int result = sqlite3_open(_dbPath.UTF8String, &_db);
if (result == SQLITE_OK) {
CFDictionaryKeyCallBacks keyCallbacks = kCFCopyStringDictionaryKeyCallBacks;
CFDictionaryValueCallBacks valueCallbacks = {0};
_dbStmtCache = CFDictionaryCreateMutable(CFAllocatorGetDefault(), 0, &keyCallbacks, &valueCallbacks);
- _dbLastOpenErrorTime = 0;
- _dbOpenErrorCount = 0;
return YES;
} else {
- _db = NULL;
- if (_dbStmtCache) CFRelease(_dbStmtCache);
- _dbStmtCache = NULL;
- _dbLastOpenErrorTime = CACurrentMediaTime();
- _dbOpenErrorCount++;
-
- if (_errorLogsEnabled) {
- NSLog(@"%s line:%d sqlite open failed (%d).", __FUNCTION__, __LINE__, result);
- }
+ NSLog(@"%s line:%d sqlite open failed (%d).", __FUNCTION__, __LINE__, result);
return NO;
}
}
- (BOOL)_dbClose {
- if (!_db) return YES;
+ BOOL needClose = YES;
+ if (!_db) {
+ needClose = NO;
+ } else if (_invalidated) {
+ needClose = NO;
+ } else if (_dbIsClosing) {
+ needClose = NO;
+ } else {
+ _dbIsClosing = YES;
+ }
+ if (!needClose) return YES;
int result = 0;
BOOL retry = NO;
@@ -140,25 +118,16 @@ - (BOOL)_dbClose {
}
}
} else if (result != SQLITE_OK) {
- if (_errorLogsEnabled) {
- NSLog(@"%s line:%d sqlite close failed (%d).", __FUNCTION__, __LINE__, result);
- }
+ NSLog(@"%s line:%d sqlite close failed (%d).", __FUNCTION__, __LINE__, result);
}
} while (retry);
_db = NULL;
+ _dbIsClosing = NO;
return YES;
}
-- (BOOL)_dbCheck {
- if (!_db) {
- if (_dbOpenErrorCount < kMaxErrorRetryCount &&
- CACurrentMediaTime() - _dbLastOpenErrorTime > kMinRetryTimeInterval) {
- return [self _dbOpen] && [self _dbInitialize];
- } else {
- return NO;
- }
- }
- return YES;
+- (BOOL)_dbIsReady {
+ return (_db && !_dbIsClosing && !_invalidated);
}
- (BOOL)_dbInitialize {
@@ -167,14 +136,14 @@ - (BOOL)_dbInitialize {
}
- (void)_dbCheckpoint {
- if (![self _dbCheck]) return;
+ if (![self _dbIsReady]) return;
// Cause a checkpoint to occur, merge `sqlite-wal` file to `sqlite` file.
sqlite3_wal_checkpoint(_db, NULL);
}
- (BOOL)_dbExecute:(NSString *)sql {
if (sql.length == 0) return NO;
- if (![self _dbCheck]) return NO;
+ if (![self _dbIsReady]) return NO;
char *error = NULL;
int result = sqlite3_exec(_db, sql.UTF8String, NULL, NULL, &error);
@@ -187,7 +156,7 @@ - (BOOL)_dbExecute:(NSString *)sql {
}
- (sqlite3_stmt *)_dbPrepareStmt:(NSString *)sql {
- if (![self _dbCheck] || sql.length == 0 || !_dbStmtCache) return NULL;
+ if (![self _dbIsReady] || sql.length == 0 || !_dbStmtCache) return NULL;
sqlite3_stmt *stmt = (sqlite3_stmt *)CFDictionaryGetValue(_dbStmtCache, (__bridge const void *)(sql));
if (!stmt) {
int result = sqlite3_prepare_v2(_db, sql.UTF8String, -1, &stmt, NULL);
@@ -261,7 +230,7 @@ - (BOOL)_dbUpdateAccessTimeWithKey:(NSString *)key {
}
- (BOOL)_dbUpdateAccessTimeWithKeys:(NSArray *)keys {
- if (![self _dbCheck]) return NO;
+ if (![self _dbIsReady]) return NO;
int t = (int)time(NULL);
NSString *sql = [NSString stringWithFormat:@"update manifest set last_access_time = %d where key in (%@);", t, [self _dbJoinedKeys:keys]];
@@ -297,7 +266,7 @@ - (BOOL)_dbDeleteItemWithKey:(NSString *)key {
}
- (BOOL)_dbDeleteItemWithKeys:(NSArray *)keys {
- if (![self _dbCheck]) return NO;
+ if (![self _dbIsReady]) return NO;
NSString *sql = [NSString stringWithFormat:@"delete from manifest where key in (%@);", [self _dbJoinedKeys:keys]];
sqlite3_stmt *stmt = NULL;
int result = sqlite3_prepare_v2(_db, sql.UTF8String, -1, &stmt, NULL);
@@ -384,7 +353,7 @@ - (YYKVStorageItem *)_dbGetItemWithKey:(NSString *)key excludeInlineData:(BOOL)e
}
- (NSMutableArray *)_dbGetItemWithKeys:(NSArray *)keys excludeInlineData:(BOOL)excludeInlineData {
- if (![self _dbCheck]) return nil;
+ if (![self _dbIsReady]) return nil;
NSString *sql;
if (excludeInlineData) {
sql = [NSString stringWithFormat:@"select key, filename, size, modification_time, last_access_time, extended_data from manifest where key in (%@);", [self _dbJoinedKeys:keys]];
@@ -458,7 +427,7 @@ - (NSString *)_dbGetFilenameWithKey:(NSString *)key {
}
- (NSMutableArray *)_dbGetFilenameWithKeys:(NSArray *)keys {
- if (![self _dbCheck]) return nil;
+ if (![self _dbIsReady]) return nil;
NSString *sql = [NSString stringWithFormat:@"select filename from manifest where key in (%@);", [self _dbJoinedKeys:keys]];
sqlite3_stmt *stmt = NULL;
int result = sqlite3_prepare_v2(_db, sql.UTF8String, -1, &stmt, NULL);
@@ -541,8 +510,8 @@ - (NSMutableArray *)_dbGetFilenamesWithTimeEarlierThan:(int)time {
return filenames;
}
-- (NSMutableArray *)_dbGetItemSizeInfoOrderByTimeAscWithLimit:(int)count {
- NSString *sql = @"select key, filename, size from manifest order by last_access_time asc limit ?1;";
+- (NSMutableArray *)_dbGetItemSizeInfoOrderByTimeDescWithLimit:(int)count {
+ NSString *sql = @"select key, filename, size from manifest order by last_access_time desc limit ?1;";
sqlite3_stmt *stmt = [self _dbPrepareStmt:sql];
if (!stmt) return nil;
sqlite3_bind_int(stmt, 1, count);
@@ -611,22 +580,26 @@ - (int)_dbGetTotalItemCount {
#pragma mark - file
- (BOOL)_fileWriteWithName:(NSString *)filename data:(NSData *)data {
+ if (_invalidated) return NO;
NSString *path = [_dataPath stringByAppendingPathComponent:filename];
return [data writeToFile:path atomically:NO];
}
- (NSData *)_fileReadWithName:(NSString *)filename {
+ if (_invalidated) return nil;
NSString *path = [_dataPath stringByAppendingPathComponent:filename];
NSData *data = [NSData dataWithContentsOfFile:path];
return data;
}
- (BOOL)_fileDeleteWithName:(NSString *)filename {
+ if (_invalidated) return NO;
NSString *path = [_dataPath stringByAppendingPathComponent:filename];
return [[NSFileManager defaultManager] removeItemAtPath:path error:NULL];
}
- (BOOL)_fileMoveAllToTrash {
+ if (_invalidated) return NO;
CFUUIDRef uuidRef = CFUUIDCreate(NULL);
CFStringRef uuid = CFUUIDCreateString(NULL, uuidRef);
CFRelease(uuidRef);
@@ -640,6 +613,7 @@ - (BOOL)_fileMoveAllToTrash {
}
- (void)_fileEmptyTrashInBackground {
+ if (_invalidated) return;
NSString *trashPath = _trashPath;
dispatch_queue_t queue = _trashQueue;
dispatch_async(queue, ^{
@@ -667,6 +641,10 @@ - (void)_reset {
[self _fileEmptyTrashInBackground];
}
+- (void)_appWillBeTerminated {
+ _invalidated = YES;
+}
+
#pragma mark - public
- (instancetype)init {
@@ -720,15 +698,13 @@ - (instancetype)initWithPath:(NSString *)path type:(YYKVStorageType)type {
return nil;
}
[self _fileEmptyTrashInBackground]; // empty the trash if failed at last time
+ [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_appWillBeTerminated) name:UIApplicationWillTerminateNotification object:nil];
return self;
}
- (void)dealloc {
- UIBackgroundTaskIdentifier taskID = [_YYSharedApplication() beginBackgroundTaskWithExpirationHandler:^{}];
+ [[NSNotificationCenter defaultCenter] removeObserver:self name:UIApplicationWillTerminateNotification object:nil];
[self _dbClose];
- if (taskID != UIBackgroundTaskInvalid) {
- [_YYSharedApplication() endBackgroundTask:taskID];
- }
}
- (BOOL)saveItem:(YYKVStorageItem *)item {
@@ -865,7 +841,7 @@ - (BOOL)removeItemsToFitSize:(int)maxSize {
BOOL suc = NO;
do {
int perCount = 16;
- items = [self _dbGetItemSizeInfoOrderByTimeAscWithLimit:perCount];
+ items = [self _dbGetItemSizeInfoOrderByTimeDescWithLimit:perCount];
for (YYKVStorageItem *item in items) {
if (total > maxSize) {
if (item.filename) {
@@ -895,7 +871,7 @@ - (BOOL)removeItemsToFitCount:(int)maxCount {
BOOL suc = NO;
do {
int perCount = 16;
- items = [self _dbGetItemSizeInfoOrderByTimeAscWithLimit:perCount];
+ items = [self _dbGetItemSizeInfoOrderByTimeDescWithLimit:perCount];
for (YYKVStorageItem *item in items) {
if (total > maxCount) {
if (item.filename) {
@@ -933,7 +909,7 @@ - (void)removeAllItemsWithProgressBlock:(void(^)(int removedCount, int totalCoun
NSArray *items = nil;
BOOL suc = NO;
do {
- items = [self _dbGetItemSizeInfoOrderByTimeAscWithLimit:perCount];
+ items = [self _dbGetItemSizeInfoOrderByTimeDescWithLimit:perCount];
for (YYKVStorageItem *item in items) {
if (left > 0) {
if (item.filename) {
diff --git a/YYWebImage/Cache/YYMemoryCache.m b/YYWebImage/Cache/YYMemoryCache.m
index 9042d9b..5c078b2 100644
--- a/YYWebImage/Cache/YYMemoryCache.m
+++ b/YYWebImage/Cache/YYMemoryCache.m
@@ -360,16 +360,16 @@ - (NSUInteger)totalCost {
return totalCost;
}
-- (BOOL)releaseOnMainThread {
+- (BOOL)releaseInMainThread {
pthread_mutex_lock(&_lock);
- BOOL releaseOnMainThread = _lru->_releaseOnMainThread;
+ BOOL releaseInMainThread = _lru->_releaseOnMainThread;
pthread_mutex_unlock(&_lock);
- return releaseOnMainThread;
+ return releaseInMainThread;
}
-- (void)setReleaseOnMainThread:(BOOL)releaseOnMainThread {
+- (void)setReleaseInMainThread:(BOOL)releaseInMainThread {
pthread_mutex_lock(&_lock);
- _lru->_releaseOnMainThread = releaseOnMainThread;
+ _lru->_releaseOnMainThread = releaseInMainThread;
pthread_mutex_unlock(&_lock);
}
diff --git a/YYWebImage/Image/YYAnimatedImageView.h b/YYWebImage/Image/YYAnimatedImageView.h
index 7412278..e70a654 100644
--- a/YYWebImage/Image/YYAnimatedImageView.h
+++ b/YYWebImage/Image/YYAnimatedImageView.h
@@ -11,8 +11,6 @@
#import
-@protocol YYAnimatedImage;
-
NS_ASSUME_NONNULL_BEGIN
/**
@@ -82,12 +80,6 @@ NS_ASSUME_NONNULL_BEGIN
*/
@property (nonatomic) NSUInteger maxBufferSize;
-/**
- * A convenience accessor for the getting the animated image that the image view is currently displaying
- * If the `image` property does not contain an animated image, this property returns nil.
- */
-@property (nonatomic, strong, nullable) UIImage *animatedImage;
-
@end
diff --git a/YYWebImage/Image/YYAnimatedImageView.m b/YYWebImage/Image/YYAnimatedImageView.m
index 7072fc8..5f2bcb4 100644
--- a/YYWebImage/Image/YYAnimatedImageView.m
+++ b/YYWebImage/Image/YYAnimatedImageView.m
@@ -301,20 +301,6 @@ - (void)setHighlighted:(BOOL)highlighted {
[self imageChanged];
}
-- (void)setAnimatedImage:(UIImage *)animatedImage {
- if (self.image == animatedImage) {
- return;
- }
- [self setImage:animatedImage withType:YYAnimatedImageTypeImage];
-}
-
-- (UIImage *)animatedImage {
- if (![self.image conformsToProtocol:@protocol(YYAnimatedImage)]) {
- return nil;
- }
- return (UIImage *)self.image;
-}
-
- (id)imageForType:(YYAnimatedImageType)type {
switch (type) {
case YYAnimatedImageTypeNone: return nil;