三肋乍、SDWebImage源碼解讀UIImageView+WebCache

UIImageView+WebCache這個類別是我們常用到的蒲祈,我相信絕大部分的程序員都看過其中的內(nèi)容,直接上代碼

- (void)sd_setImageWithURL:(nullable NSURL *)url
- (void)sd_setImageWithURL:(nullable NSURL *)url
          placeholderImage:(nullable UIImage *)placeholder
- (void)sd_setImageWithURL:(nullable NSURL *)url
          placeholderImage:(nullable UIImage *)placeholder
                   options:(SDWebImageOptions)options
- (void)sd_setImageWithURL:(nullable NSURL *)url
                 completed:(nullable SDExternalCompletionBlock)completedBlock
- (void)sd_setImageWithURL:(nullable NSURL *)url
          placeholderImage:(nullable UIImage *)placeholder
                 completed:(nullable SDExternalCompletionBlock)completedBlock
- (void)sd_setImageWithURL:(nullable NSURL *)url
          placeholderImage:(nullable UIImage *)placeholder
                   options:(SDWebImageOptions)options
                 completed:(nullable SDExternalCompletionBlock)completedBlock
- (void)sd_setImageWithPreviousCachedImageWithURL:(nullable NSURL *)url
                                 placeholderImage:(nullable UIImage *)placeholder
                                          options:(SDWebImageOptions)options
                                         progress:(nullable SDWebImageDownloaderProgressBlock)progressBlock
                                        completed:(nullable SDExternalCompletionBlock)completedBlock

這里的設(shè)計思路值得我們學習,當你寫一個對外的接口或者方法的時候台夺,可以根據(jù)不能的需求定制不同的方法,這樣可以滿足不同需求的人痴脾,而且顯得美觀和整潔颤介。

- (void)sd_setAnimationImagesWithURLs:(nonnull NSArray<NSURL *> *)arrayOfURLs {
    [self sd_cancelCurrentAnimationImagesLoad];
    __weak __typeof(self)wself = self;

    NSPointerArray *operationsArray = [self sd_animationOperationArray];
    //這個方法,遍歷字典和量大的數(shù)組和遍歷字典時性能比 for in 好,且代碼更加優(yōu)雅;對于單個數(shù)組使用for in 新能更好
    [arrayOfURLs enumerateObjectsUsingBlock:^(NSURL *logoImageURL, NSUInteger idx, BOOL * _Nonnull stop) {//遍歷urls
        id <SDWebImageOperation> operation = [[SDWebImageManager sharedManager] loadImageWithURL:logoImageURL options:0 progress:nil completed:^(UIImage *image, NSData *data, NSError *error, SDImageCacheType cacheType, BOOL finished, NSURL *imageURL) {
            if (!wself) return;
            dispatch_main_async_safe(^{
                __strong UIImageView *sself = wself;
                [sself stopAnimating];
                if (sself && image) {
                    NSMutableArray<UIImage *> *currentImages = [[sself animationImages] mutableCopy];//處理gif圖像
                    if (!currentImages) {
                        currentImages = [[NSMutableArray alloc] init];
                    }
                    
                    // We know what index objects should be at when they are returned so
                    // we will put the object at the index, filling any empty indexes
                    // with the image that was returned too "early". These images will
                    // be overwritten. (does not require additional sorting datastructure)
                    while ([currentImages count] < idx) { //若gif圖片將靜態(tài)數(shù)組添加到數(shù)組中
                        [currentImages addObject:image];
                    }
                    
                    currentImages[idx] = image;

                    sself.animationImages = currentImages;
                    [sself setNeedsLayout];
                }
                [sself startAnimating];
            });
        }];
        @synchronized (self) {
            [operationsArray addPointer:(__bridge void *)(operation)]; //添加operation
        }
    }];
}

static char animationLoadOperationKey;

// element is weak because operation instance is retained by SDWebImageManager's runningOperations property
// we should use lock to keep thread-safe because these method may not be acessed from main queue
- (NSPointerArray *)sd_animationOperationArray {
    @synchronized(self) {
        NSPointerArray *operationsArray = objc_getAssociatedObject(self, &animationLoadOperationKey);//關(guān)聯(lián)對象
        if (operationsArray) {
            return operationsArray;
        }
        operationsArray = [NSPointerArray weakObjectsPointerArray]; //建立弱連接
        objc_setAssociatedObject(self, &animationLoadOperationKey, operationsArray, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
        return operationsArray;
    }
}

- (void)sd_cancelCurrentAnimationImagesLoad {
    NSPointerArray *operationsArray = [self sd_animationOperationArray];
    if (operationsArray) {
        @synchronized (self) {//同步鎖,防止多線程同時訪問
            for (id operation in operationsArray) {
                if ([operation conformsToProtocol:@protocol(SDWebImageOperation)]) { // operation 是否遵守SDWebImageOperation協(xié)議
                    [operation cancel]; //取消
                }
            }
            operationsArray.count = 0;
        }
    }
}

擴展知識
1.NSMapTable赞赖, NSHashTable NSPointerArray
現(xiàn)在我們雖然都在用ARC,但是有時候我們需要精確的知道我們是不是在dic滚朵,set,和array中持有還是不持有對象前域,但是NSDictionary辕近,NSSet,NSArray匿垄,所以我們需要NSMapTable移宅, NSHashTable NSPointerArray
以NSPointerArray為例

+ (NSPointerArray *)strongObjectsPointerArray //建立強連接
+ (NSPointerArray *)weakObjectsPointerArray //建立弱連接
  1. enumerateObjectsUsingBlock 這個方法,遍歷字典和量大的數(shù)組和遍歷字典時性能比 for in 好,且代碼更加優(yōu)雅;對于單個數(shù)組使用for in 新能更好 在很多框架中都被使用,以利用到多核cpu的優(yōu)勢
    用法:
    NSArray 和 NSSet 都可以使用
  • (void)enumerateObjectsUsingBlock:(void (NS_NOESCAPE ^)(ObjectType obj, NSUInteger idx, BOOL *stop))block
  • (void)enumerateObjectsWithOptions:(NSEnumerationOptions)opts usingBlock:(void (NS_NOESCAPE ^)(ObjectType obj, NSUInteger idx, BOOL *stop))block

NSDictionary 使用

  • (void)enumerateKeysAndObjectsUsingBlock:(void (NS_NOESCAPE ^)(KeyType key, ObjectType obj, BOOL *stop))block
  • (void)enumerateKeysAndObjectsWithOptions:(NSEnumerationOptions)opts usingBlock:(void (NS_NOESCAPE ^)(KeyType key, ObjectType obj, BOOL *stop))block

NSEnumerationConcurrent 順序
NSEnumerationReverse 倒序

例子:

NSArray :
NSArray *array = @[@"a", @"b", @"c"];
    for (NSString *str in [array reverseObjectEnumerator]) { //reverseObjectEnumerator倒序 objectEnumerator 正序
    }
 [array enumerateObjectsWithOptions:NSEnumerationReverse usingBlock:^(Sark *sark, NSUInteger idx, BOOL *stop) {
    }];

NSDictionary:
NSDictionary *dict = @{@"a": @"1", @"b": @"2"};
    [dict enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) {
    NSLog(@"key: %@, value: %@", key, obj);
    }];

**
遍歷執(zhí)行block會分配在多核cpu上執(zhí)行椿疗,底層可能是GCD的并發(fā)queue漏峰,對于耗時的任務(wù)來說是不錯的選擇,同事届榄,對于遍歷的外部是保持同步的芽狗,遍歷都完成后才繼續(xù)執(zhí)行下一行。
**

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末痒蓬,一起剝皮案震驚了整個濱河市童擎,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌攻晒,老刑警劉巖顾复,帶你破解...
    沈念sama閱讀 219,490評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異鲁捏,居然都是意外死亡芯砸,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,581評論 3 395
  • 文/潘曉璐 我一進店門给梅,熙熙樓的掌柜王于貴愁眉苦臉地迎上來假丧,“玉大人,你說我怎么就攤上這事动羽“悖” “怎么了?”我有些...
    開封第一講書人閱讀 165,830評論 0 356
  • 文/不壞的土叔 我叫張陵运吓,是天一觀的道長渴邦。 經(jīng)常有香客問我,道長拘哨,這世上最難降的妖魔是什么谋梭? 我笑而不...
    開封第一講書人閱讀 58,957評論 1 295
  • 正文 為了忘掉前任耸成,我火速辦了婚禮叙身,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘叙量。我一直安慰自己产镐,他們只是感情好隘庄,可當我...
    茶點故事閱讀 67,974評論 6 393
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著磷账,像睡著了一般峭沦。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上逃糟,一...
    開封第一講書人閱讀 51,754評論 1 307
  • 那天吼鱼,我揣著相機與錄音,去河邊找鬼绰咽。 笑死菇肃,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的取募。 我是一名探鬼主播琐谤,決...
    沈念sama閱讀 40,464評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼玩敏!你這毒婦竟也來了斗忌?” 一聲冷哼從身側(cè)響起质礼,我...
    開封第一講書人閱讀 39,357評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎织阳,沒想到半個月后眶蕉,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,847評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡唧躲,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,995評論 3 338
  • 正文 我和宋清朗相戀三年造挽,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片弄痹。...
    茶點故事閱讀 40,137評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡饭入,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出肛真,到底是詐尸還是另有隱情谐丢,我是刑警寧澤,帶...
    沈念sama閱讀 35,819評論 5 346
  • 正文 年R本政府宣布毁欣,位于F島的核電站庇谆,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏凭疮。R本人自食惡果不足惜饭耳,卻給世界環(huán)境...
    茶點故事閱讀 41,482評論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望执解。 院中可真熱鬧寞肖,春花似錦、人聲如沸衰腌。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,023評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽右蕊。三九已至琼稻,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間饶囚,已是汗流浹背帕翻。 一陣腳步聲響...
    開封第一講書人閱讀 33,149評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留萝风,地道東北人嘀掸。 一個月前我還...
    沈念sama閱讀 48,409評論 3 373
  • 正文 我出身青樓,卻偏偏與公主長得像规惰,于是被迫代替她去往敵國和親睬塌。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 45,086評論 2 355

推薦閱讀更多精彩內(nèi)容