iOS多線程與網(wǎng)絡(luò)(2)--單例模式、NSoperation

補(bǔ)充

使用Crearte函數(shù)創(chuàng)建的并發(fā)隊(duì)列和全局并發(fā)隊(duì)列的主要區(qū)別:
1.全局并發(fā)隊(duì)列在整個(gè)應(yīng)用程序中本身是默認(rèn)存在的,并且對(duì)應(yīng)有高優(yōu)先級(jí)垮庐、默認(rèn)優(yōu)先級(jí)银觅、低優(yōu)先級(jí)和后臺(tái)優(yōu)先級(jí)一共四個(gè)并發(fā)隊(duì)列,我們只是選擇其中的一個(gè)直接拿來(lái)用践宴。而Crearte函數(shù)是實(shí)打?qū)嵉膹念^開始去創(chuàng)建一個(gè)隊(duì)列鲸匿。
2.在iOS6.0之前,在GCD中凡是使用了帶Create和retain的函數(shù)在最后都需要做一次release操作浴井。而主隊(duì)列和全局并發(fā)隊(duì)列不需要我們手動(dòng)release晒骇。當(dāng)然了,在iOS6.0之后GCD已經(jīng)被納入到了ARC的內(nèi)存管理范疇中,即便是使用retain或者create函數(shù)創(chuàng)建的對(duì)象也不再需要開發(fā)人員手動(dòng)釋放洪囤,我們像對(duì)待普通OC對(duì)象一樣對(duì)待GCD就OK徒坡。
3.在使用柵欄函數(shù)的時(shí)候,蘋果官方明確規(guī)定柵欄函數(shù)只有在和使用create函數(shù)自己的創(chuàng)建的并發(fā)隊(duì)列一起使用的時(shí)候才有效(沒(méi)有給出具體原因)
4.其它區(qū)別涉及到XNU內(nèi)核的系統(tǒng)級(jí)線程編程瘤缩,不一一列舉喇完。
5.給出一些參考資料(可以自行研究):

GCDAPI:https://developer.apple.com/library/ios/documentation/Performance/Reference/GCD_libdispatch_Ref/index.html#//apple_ref/c/func/dispatch_queue_create

Libdispatch版本源碼:http://www.opensource.apple.com/source/libdispatch/libdispatch-187.5/

1.單例模式

  • 1.1 概念相關(guān)

(1)單例模式

在程序運(yùn)行過(guò)程,一個(gè)類只有一個(gè)實(shí)例

(2)使用場(chǎng)合

在整個(gè)應(yīng)用程序中剥啤,共享一份資源(這份資源只需要?jiǎng)?chuàng)建初始化1次)
  • 1.2 ARC實(shí)現(xiàn)單例

(1)步驟

01 在類的內(nèi)部提供一個(gè)static修飾的全局變量
02 提供一個(gè)類方法锦溪,方便外界訪問(wèn)
03 重寫+allocWithZone方法,保證永遠(yuǎn)都只為單例對(duì)象分配一次內(nèi)存空間
04 嚴(yán)謹(jǐn)起見(jiàn)府怯,重寫-copyWithZone方法和-MutableCopyWithZone方法

(2)相關(guān)代碼

//提供一個(gè)static修飾的全局變量刻诊,強(qiáng)引用著已經(jīng)實(shí)例化的單例對(duì)象實(shí)例
static XMGTools *_instance;

//類方法,返回一個(gè)單例對(duì)象
+(instancetype)shareTools
{
     //注意:這里建議使用self,而不是直接使用類名Tools(考慮繼承)

    return [[self alloc]init];
}

//保證永遠(yuǎn)只分配一次存儲(chǔ)空間
+(instancetype)allocWithZone:(struct _NSZone *)zone
{
    //使用GCD中的一次性代碼
//    static dispatch_once_t onceToken;
//    dispatch_once(&onceToken, ^{
//        _instance = [super allocWithZone:zone];
//    });

    //使用加鎖的方式牺丙,保證只分配一次存儲(chǔ)空間
    @synchronized(self) {
        if (_instance == nil) {
            _instance = [super allocWithZone:zone];
        }
    }
    return _instance;
}
/*
1. mutableCopy 創(chuàng)建一個(gè)新的可變對(duì)象则涯,并初始化為原對(duì)象的值,新對(duì)象的引用計(jì)數(shù)為 1冲簿;
2. copy 返回一個(gè)不可變對(duì)象粟判。分兩種情況:(1)若原對(duì)象是不可變對(duì)象,那么返回原對(duì)象峦剔,并將其引用計(jì)數(shù)加 1 档礁;(2)若原對(duì)象是可變對(duì)象,那么創(chuàng)建一個(gè)新的不可變對(duì)象吝沫,并初始化為原對(duì)象的值呻澜,新對(duì)象的引用計(jì)數(shù)為 1。
*/
//讓代碼更加的嚴(yán)謹(jǐn)
-(nonnull id)copyWithZone:(nullable NSZone *)zone
{
//    return [[self class] allocWithZone:zone];
    return _instance;
}

-(nonnull id)mutableCopyWithZone:(nullable NSZone *)zone
{
    return _instance;
}

  • 1.3 MRC實(shí)現(xiàn)單例

(1)實(shí)現(xiàn)步驟

01 在類的內(nèi)部提供一個(gè)static修飾的全局變量
02 提供一個(gè)類方法野舶,方便外界訪問(wèn)
03 重寫+allocWithZone方法易迹,保證永遠(yuǎn)都只為單例對(duì)象分配一次內(nèi)存空間
04 嚴(yán)謹(jǐn)起見(jiàn),重寫-copyWithZone方法和-MutableCopyWithZone方法
05 重寫release方法
06 重寫retain方法
07 建議在retainCount方法中返回一個(gè)最大值

(2)配置MRC環(huán)境知識(shí)

01 注意ARC不是垃圾回收機(jī)制平道,是編譯器特性
02 配置MRC環(huán)境:build setting ->搜索automatic ref->修改為NO

(3)相關(guān)代碼

//提供一個(gè)static修飾的全局變量睹欲,強(qiáng)引用著已經(jīng)實(shí)例化的單例對(duì)象實(shí)例
static XMGTools *_instance;

//類方法,返回一個(gè)單例對(duì)象
+(instancetype)shareTools
{
     //注意:這里建議使用self,而不是直接使用類名Tools(考慮繼承)

    return [[self alloc]init];
}

//保證永遠(yuǎn)只分配一次存儲(chǔ)空間
+(instancetype)allocWithZone:(struct _NSZone *)zone
{
    //使用GCD中的一次性代碼
//    static dispatch_once_t onceToken;
//    dispatch_once(&onceToken, ^{
//        _instance = [super allocWithZone:zone];
//    });

    //使用加鎖的方式一屋,保證只分配一次存儲(chǔ)空間
    @synchronized(self) {
        if (_instance == nil) {
            _instance = [super allocWithZone:zone];
        }
    }
    return _instance;
}

//讓代碼更加的嚴(yán)謹(jǐn)
-(nonnull id)copyWithZone:(nullable NSZone *)zone
{
//    return [[self class] allocWithZone:zone];
    return _instance;
}

-(nonnull id)mutableCopyWithZone:(nullable NSZone *)zone
{
    return _instance;
}

//在MRC環(huán)境下窘疮,如果用戶retain了一次,那么直接返回instance變量冀墨,不對(duì)引用計(jì)數(shù)器+1
//如果用戶release了一次闸衫,那么什么都不做,因?yàn)閱卫J皆谡麄€(gè)程序運(yùn)行過(guò)程中都擁有且只有一份诽嘉,程序退出之后被釋放蔚出,所以不需要對(duì)引用計(jì)數(shù)器操作
-(oneway void)release
{
}

-(instancetype)retain
{
    return _instance;
}

//慣用法弟翘,有經(jīng)驗(yàn)的程序員通過(guò)打印retainCount這個(gè)值可以猜到這是一個(gè)單例
-(NSUInteger)retainCount
{
    return MAXFLOAT;
}

  • 1.4 通用版本

(1)有意思的對(duì)話

01 問(wèn):寫一份單例代碼在ARC和MRC環(huán)境下都適用?
答:可以使用條件編譯來(lái)判斷當(dāng)前項(xiàng)目環(huán)境是ARC還是MRC
02 問(wèn):條件編譯的代碼呢骄酗,么么噠稀余?
//答:條件編譯
#if __has_feature(objc_arc)
//如果是ARC,那么就執(zhí)行這里的代碼1
#else
//如果不是ARC趋翻,那么就執(zhí)行代理的代碼2
#endif
03 問(wèn):在項(xiàng)目里面往往需要實(shí)現(xiàn)很多的單例睛琳,比如下載、網(wǎng)絡(luò)請(qǐng)求踏烙、音樂(lè)播放等等师骗,弱弱的問(wèn)一句單例可以用繼承嗎?
答:?jiǎn)卫遣豢梢杂美^承的讨惩,如果想一次寫就辟癌,四處使用,那么推薦親使用帶參數(shù)的宏定義啦步脓!
04 問(wèn):宏定義怎么弄愿待?
答:這個(gè)嘛~~回頭看一眼我的代碼咯浩螺,親靴患。

(2)使用帶參數(shù)的宏完成通用版單例模式代碼

01 注意條件編譯的代碼不能包含在宏定義里面
02 宏定義的代碼只需要寫一次就好,之后直接拖到項(xiàng)目中用就OK

2.NSOperation

  • 2.1 NSOperation基本使用

(1)相關(guān)概念

01 NSOperation是對(duì)GCD的包裝
02 兩個(gè)核心概念【隊(duì)列+操作】

(2)基本使用

01 NSOperation本身是抽象類要出,只能只有它的子類
02 三個(gè)子類分別是:NSBlockOperation鸳君、NSInvocationOperation以及自定義繼承自NSOperation的類
03 NSOperation和NSOperationQueue結(jié)合使用實(shí)現(xiàn)多線程并發(fā)

(3)相關(guān)代碼

//  01 NSInvocationOperation
    //1.封裝操作
    /*
     第一個(gè)參數(shù):目標(biāo)對(duì)象
     第二個(gè)參數(shù):該操作要調(diào)用的方法,最多接受一個(gè)參數(shù)
     第三個(gè)參數(shù):調(diào)用方法傳遞的參數(shù)患蹂,如果方法不接受參數(shù)或颊,那么該值傳nil
     */
    NSInvocationOperation *operation = [[NSInvocationOperation alloc]
                                        initWithTarget:self selector:@selector(run) object:nil];

    //2.啟動(dòng)操作
    [operation start];
-------------------------------------------------
    //  02 NSBlockOperation
    //1.封裝操作
    /*
     NSBlockOperation提供了一個(gè)類方法,在該類方法中封裝操作
     */
    NSBlockOperation *operation = [NSBlockOperation blockOperationWithBlock:^{
        //在主線程中執(zhí)行
        NSLog(@"---download1--%@",[NSThread currentThread]);
    }];

    //2.追加操作传于,追加的操作在子線程中執(zhí)行
    [operation addExecutionBlock:^{
        NSLog(@"---download2--%@",[NSThread currentThread]);
    }];

    [operation addExecutionBlock:^{
         NSLog(@"---download3--%@",[NSThread currentThread]);
    }];

    //3.啟動(dòng)執(zhí)行操作
    [operation start];

----------------------------------------------
// 03 自定義NSOperation
    //如何封裝操作囱挑?
    //自定義的NSOperation,通過(guò)重寫內(nèi)部的main方法實(shí)現(xiàn)封裝操作
    -(void)main
    {
        NSLog(@"--main--%@",[NSThread currentThread]);
    }

    //如何使用?
    //1.實(shí)例化一個(gè)自定義操作對(duì)象
    XMGOperation *op = [[XMGOperation alloc]init];

    //2.執(zhí)行操作
    [op start];
  • 2.2 NSOperationQueue基本使用

(1)NSOperation中的兩種隊(duì)列

01 主隊(duì)列 通過(guò)mainQueue獲得沼溜,凡是放到主隊(duì)列中的任務(wù)都將在主線程執(zhí)行
02 非主隊(duì)列 直接alloc init出來(lái)的隊(duì)列平挑。非主隊(duì)列同時(shí)具備了并發(fā)和串行的功能,通過(guò)設(shè)置最大并發(fā)數(shù)屬性來(lái)控制任務(wù)是并發(fā)執(zhí)行還是串行執(zhí)行

(2)相關(guān)代碼

//自定義NSOperation
-(void)customOperation
{
    //1.創(chuàng)建隊(duì)列
    NSOperationQueue *queue = [[NSOperationQueue alloc]init];

    //2.封裝操作
    //好處:1.信息隱蔽
    //2.代碼復(fù)用

    XMGOperation *op1 = [[XMGOperation alloc]init];
    XMGOperation *op2 = [[XMGOperation alloc]init];

    //3.添加操作到隊(duì)列中
    [queue addOperation:op1];
    [queue addOperation:op2];
}

//NSBlockOperation
- (void)block
{
    //1.創(chuàng)建隊(duì)列
    NSOperationQueue *queue = [[NSOperationQueue alloc]init];

    //2.封裝操作
    NSBlockOperation *op1 = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"1----%@",[NSThread currentThread]);
    }];

    NSBlockOperation *op2 = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"2----%@",[NSThread currentThread]);

    }];

    [op2 addExecutionBlock:^{
        NSLog(@"3----%@",[NSThread currentThread]);
    }];

    [op2 addExecutionBlock:^{
        NSLog(@"4----%@",[NSThread currentThread]);
    }];

    //3.添加操作到隊(duì)列中
    [queue addOperation:op1];
    [queue addOperation:op2];

    //補(bǔ)充:簡(jiǎn)便方法
    [queue addOperationWithBlock:^{
        NSLog(@"5----%@",[NSThread currentThread]);
    }];

}

//NSInvocationOperation
- (void)invocation
{
    /*
     GCD中的隊(duì)列:
     串行隊(duì)列:自己創(chuàng)建的系草,主隊(duì)列
     并發(fā)隊(duì)列:自己創(chuàng)建的通熄,全局并發(fā)隊(duì)列

     NSOperationQueue
     主隊(duì)列:[NSOperationQueue mainqueue];凡事放在主隊(duì)列中的操作都在主線程中執(zhí)行
     非主隊(duì)列:[[NSOperationQueue alloc]init],并發(fā)和串行找都,默認(rèn)是并發(fā)執(zhí)行的
     */

    //1.創(chuàng)建隊(duì)列
    NSOperationQueue *queue = [[NSOperationQueue alloc]init];

    //2.封裝操作
    NSInvocationOperation *op1 = [[NSInvocationOperation alloc]initWithTarget:self selector:@selector(download1) object:nil];

    NSInvocationOperation *op2 = [[NSInvocationOperation alloc]initWithTarget:self selector:@selector(download2) object:nil];


    NSInvocationOperation *op3 = [[NSInvocationOperation alloc]initWithTarget:self selector:@selector(download3) object:nil];


    //3.把封裝好的操作添加到隊(duì)列中
    [queue addOperation:op1];//[op1 start]
    [queue addOperation:op2];
    [queue addOperation:op3];
}

  • 2.3 NSOperation其它用法

(1)設(shè)置最大并發(fā)數(shù)【控制任務(wù)并發(fā)和串行】

//1.創(chuàng)建隊(duì)列
    NSOperationQueue *queue = [[NSOperationQueue alloc]init];

    //2.設(shè)置最大并發(fā)數(shù)
    //注意點(diǎn):該屬性需要在任務(wù)添加到隊(duì)列中之前進(jìn)行設(shè)置
    //該屬性控制隊(duì)列是串行執(zhí)行還是并發(fā)執(zhí)行
    //如果最大并發(fā)數(shù)等于1唇辨,那么該隊(duì)列是串行的,如果大于1那么是并行的
    //系統(tǒng)的最大并發(fā)數(shù)有個(gè)默認(rèn)的值能耻,為-1赏枚,如果該屬性設(shè)置為0亡驰,那么不會(huì)執(zhí)行任何任務(wù)
    queue.maxConcurrentOperationCount = 2;

(2)暫停和恢復(fù)以及取消

    //設(shè)置暫停和恢復(fù)
    //suspended設(shè)置為YES表示暫停,suspended設(shè)置為NO表示恢復(fù)
    //暫停表示不繼續(xù)執(zhí)行隊(duì)列中的下一個(gè)任務(wù)饿幅,暫停操作是可以恢復(fù)的
    if (self.queue.isSuspended) {
        self.queue.suspended = NO;
    }else
    {
        self.queue.suspended = YES;
    }

    //取消隊(duì)列里面的所有操作
    //取消之后隐解,當(dāng)前正在執(zhí)行的操作的下一個(gè)操作將不再執(zhí)行,而且永遠(yuǎn)都不在執(zhí)行诫睬,就像后面的所有任務(wù)都從隊(duì)列里面移除了一樣
    //取消操作是不可以恢復(fù)的
    [self.queue cancelAllOperations];

---------自定義NSOperation取消操作--------------------------
-(void)main
{
    //耗時(shí)操作1
    for (int i = 0; i<1000; i++) {
        NSLog(@"任務(wù)1-%d--%@",i,[NSThread currentThread]);
    }
    NSLog(@"+++++++++++++++++++++++++++++++++");

    //蘋果官方建議煞茫,每當(dāng)執(zhí)行完一次耗時(shí)操作之后,就查看一下當(dāng)前隊(duì)列是否為取消狀態(tài)摄凡,如果是续徽,那么就直接退出
    //好處是可以提高程序的性能
    if (self.isCancelled) {
        return;
    }

    //耗時(shí)操作2
    for (int i = 0; i<1000; i++) {
        NSLog(@"任務(wù)1-%d--%@",i,[NSThread currentThread]);
    }

    NSLog(@"+++++++++++++++++++++++++++++++++");
}
  • 2.4 NSOperation實(shí)現(xiàn)線程間通信

(1)開子線程下載圖片

 //1.創(chuàng)建隊(duì)列
    NSOperationQueue *queue = [[NSOperationQueue alloc]init];

    //2.使用簡(jiǎn)便方法封裝操作并添加到隊(duì)列中
    [queue addOperationWithBlock:^{

        //3.在該block中下載圖片
        NSURL *url = [NSURL URLWithString:@"http://news.51sheyuan.com/uploads/allimg/111001/133442IB-2.jpg"];
        NSData *data = [NSData dataWithContentsOfURL:url];
        UIImage *image = [UIImage imageWithData:data];
        NSLog(@"下載圖片操作--%@",[NSThread currentThread]);

        //4.回到主線程刷新UI
        [[NSOperationQueue mainQueue] addOperationWithBlock:^{
            self.imageView.image = image;
            NSLog(@"刷新UI操作---%@",[NSThread currentThread]);
        }];
    }];

(2)下載多張圖片合成綜合案例(設(shè)置操作依賴)

//02 綜合案例
- (void)download2
{
    NSLog(@"----");
    //1.創(chuàng)建隊(duì)列
    NSOperationQueue *queue = [[NSOperationQueue alloc]init];

    //2.封裝操作下載圖片1
    NSBlockOperation *op1 = [NSBlockOperation blockOperationWithBlock:^{

        NSURL *url = [NSURL URLWithString:@"http://h.hiphotos.baidu.com/zhidao/pic/item/6a63f6246b600c3320b14bb3184c510fd8f9a185.jpg"];
        NSData *data = [NSData dataWithContentsOfURL:url];

        //拿到圖片數(shù)據(jù)
        self.image1 = [UIImage imageWithData:data];
    }];


    //3.封裝操作下載圖片2
    NSBlockOperation *op2 = [NSBlockOperation blockOperationWithBlock:^{
        NSURL *url = [NSURL URLWithString:@"http://pic.58pic.com/58pic/13/87/82/27Q58PICYje_1024.jpg"];
        NSData *data = [NSData dataWithContentsOfURL:url];

        //拿到圖片數(shù)據(jù)
        self.image2 = [UIImage imageWithData:data];
    }];

    //4.合成圖片
    NSBlockOperation *combine = [NSBlockOperation blockOperationWithBlock:^{

        //4.1 開啟圖形上下文
        UIGraphicsBeginImageContext(CGSizeMake(200, 200));

        //4.2 畫image1
        [self.image1 drawInRect:CGRectMake(0, 0, 200, 100)];

        //4.3 畫image2
        [self.image2 drawInRect:CGRectMake(0, 100, 200, 100)];

        //4.4 根據(jù)圖形上下文拿到圖片數(shù)據(jù)
        UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
//        NSLog(@"%@",image);

        //4.5 關(guān)閉圖形上下文
        UIGraphicsEndImageContext();

        //7.回到主線程刷新UI
        [[NSOperationQueue mainQueue]addOperationWithBlock:^{
            self.imageView.image = image;
            NSLog(@"刷新UI---%@",[NSThread currentThread]);
        }];

    }];

    //5.設(shè)置操作依賴
    [combine addDependency:op1];
    [combine addDependency:op2];

    //6.添加操作到隊(duì)列中執(zhí)行
    [queue addOperation:op1];
    [queue addOperation:op2];
    [queue addOperation:combine];
    }

3.多圖下載綜合示例程序

(1)涉及知識(shí)點(diǎn)

     01 字典轉(zhuǎn)模型
     02 存儲(chǔ)數(shù)據(jù)到沙盒,從沙盒中加載數(shù)據(jù)
     03 占位圖片的設(shè)置(cell的刷新問(wèn)題)
     04 如何進(jìn)行內(nèi)存緩存(使用NSDictionary)
     05 在程序開發(fā)過(guò)程中的一些容錯(cuò)處理
     06 如何刷新tableView的指定行(解決數(shù)據(jù)錯(cuò)亂問(wèn)題)
     07 NSOperation以及線程間通信相關(guān)知識(shí)

4.第三方框架

(1)SDWebImage基本使用

    01 設(shè)置imageView的圖片
    [cell.imageView sd_setImageWithURL:[NSURL URLWithString:app.icon] placeholderImage:[UIImage imageNamed:@"placehoder"]];

    02 設(shè)置圖片并計(jì)算下載進(jìn)度
       //下載并設(shè)置圖片
    /*
     第一個(gè)參數(shù):要下載圖片的url地址
     第二個(gè)參數(shù):設(shè)置該imageView的占位圖片
     第三個(gè)參數(shù):傳一個(gè)枚舉值亲澡,告訴程序你下載圖片的策略是什么
     第一個(gè)block塊:獲取當(dāng)前圖片數(shù)據(jù)的下載進(jìn)度
         receivedSize:已經(jīng)下載完成的數(shù)據(jù)大小
         expectedSize:該文件的數(shù)據(jù)總大小
     第二個(gè)block塊:當(dāng)圖片下載完成之后執(zhí)行該block中的代碼
         image:下載得到的圖片數(shù)據(jù)
         error:下載出現(xiàn)的錯(cuò)誤信息
         SDImageCacheType:圖片的緩存策略(不緩存钦扭,內(nèi)存緩存,沙盒緩存)
         imageURL:下載的圖片的url地址
     */
    [cell.imageView sd_setImageWithURL:[NSURL URLWithString:app.icon] placeholderImage:[UIImage imageNamed:@"placehoder"] options:SDWebImageRetryFailed progress:^(NSInteger receivedSize, NSInteger expectedSize) {

        //計(jì)算當(dāng)前圖片的下載進(jìn)度
        NSLog(@"%.2f",1.0 *receivedSize / expectedSize);

    } completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, NSURL *imageURL) {

    }];

    03 系統(tǒng)級(jí)內(nèi)存警告如何處理(面試)
    //取消當(dāng)前正在進(jìn)行的所有下載操作
    [[SDWebImageManager sharedManager] cancelAll];

    //清除緩存數(shù)據(jù)(面試)
    //cleanDisk:刪除過(guò)期的文件數(shù)據(jù)床绪,計(jì)算當(dāng)前未過(guò)期的已經(jīng)下載的文件數(shù)據(jù)的大小客情,如果發(fā)現(xiàn)該數(shù)據(jù)大小大于我們?cè)O(shè)置的最大緩存數(shù)據(jù)大小,那么程序內(nèi)部會(huì)按照按文件數(shù)據(jù)緩存的時(shí)間從遠(yuǎn)到近刪除癞己,知道小于最大緩存數(shù)據(jù)為止膀斋。

    //clearMemory:直接刪除文件,重新創(chuàng)建新的文件夾
    //[[SDWebImageManager sharedManager].imageCache cleanDisk];
    [[SDWebImageManager sharedManager].imageCache clearMemory];

    04 SDWebImage默認(rèn)的緩存時(shí)間是1周
    05 如何播放gif圖片
    /*
    5-1 把用戶傳入的gif圖片->NSData
    5-2 根據(jù)該Data創(chuàng)建一個(gè)圖片數(shù)據(jù)源(NSData->CFImageSourceRef)
    5-3 計(jì)算該數(shù)據(jù)源中一共有多少幀痹雅,把每一幀數(shù)據(jù)取出來(lái)放到圖片數(shù)組中
    5-4 根據(jù)得到的數(shù)組+計(jì)算的動(dòng)畫時(shí)間-》可動(dòng)畫的image
    [UIImage animatedImageWithImages:images duration:duration];
    */

    06 如何判斷當(dāng)前圖片類型
    + (NSString *)sd_contentTypeForImageData:(NSData *)data;


(2)SDWebImage內(nèi)部結(jié)構(gòu)

1.png
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末仰担,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子绩社,更是在濱河造成了極大的恐慌摔蓝,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,013評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件愉耙,死亡現(xiàn)場(chǎng)離奇詭異贮尉,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)朴沿,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,205評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門猜谚,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人悯仙,你說(shuō)我怎么就攤上這事龄毡。” “怎么了锡垄?”我有些...
    開封第一講書人閱讀 152,370評(píng)論 0 342
  • 文/不壞的土叔 我叫張陵沦零,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我货岭,道長(zhǎng)路操,這世上最難降的妖魔是什么疾渴? 我笑而不...
    開封第一講書人閱讀 55,168評(píng)論 1 278
  • 正文 為了忘掉前任,我火速辦了婚禮屯仗,結(jié)果婚禮上搞坝,老公的妹妹穿的比我還像新娘。我一直安慰自己魁袜,他們只是感情好桩撮,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,153評(píng)論 5 371
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著峰弹,像睡著了一般店量。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上鞠呈,一...
    開封第一講書人閱讀 48,954評(píng)論 1 283
  • 那天融师,我揣著相機(jī)與錄音,去河邊找鬼蚁吝。 笑死旱爆,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的窘茁。 我是一名探鬼主播怀伦,決...
    沈念sama閱讀 38,271評(píng)論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼庙曙!你這毒婦竟也來(lái)了空镜?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 36,916評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤捌朴,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后张抄,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體砂蔽,經(jīng)...
    沈念sama閱讀 43,382評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,877評(píng)論 2 323
  • 正文 我和宋清朗相戀三年署惯,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了左驾。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 37,989評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡极谊,死狀恐怖诡右,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情轻猖,我是刑警寧澤帆吻,帶...
    沈念sama閱讀 33,624評(píng)論 4 322
  • 正文 年R本政府宣布,位于F島的核電站咙边,受9級(jí)特大地震影響猜煮,放射性物質(zhì)發(fā)生泄漏次员。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,209評(píng)論 3 307
  • 文/蒙蒙 一王带、第九天 我趴在偏房一處隱蔽的房頂上張望淑蔚。 院中可真熱鬧,春花似錦愕撰、人聲如沸刹衫。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,199評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)绪妹。三九已至,卻和暖如春柿究,著一層夾襖步出監(jiān)牢的瞬間邮旷,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,418評(píng)論 1 260
  • 我被黑心中介騙來(lái)泰國(guó)打工蝇摸, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留婶肩,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,401評(píng)論 2 352
  • 正文 我出身青樓貌夕,卻偏偏與公主長(zhǎng)得像律歼,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子啡专,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,700評(píng)論 2 345

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

  • *面試心聲:其實(shí)這些題本人都沒(méi)怎么背,但是在上海 兩周半 面了大約10家 收到差不多3個(gè)offer,總結(jié)起來(lái)就是把...
    Dove_iOS閱讀 27,124評(píng)論 29 470
  • 1.iOS 中的單例 1.1 ARC實(shí)現(xiàn)單例 (1)步驟01 在類的內(nèi)部提供一個(gè)static修飾的全局變量02 提...
    iOS小王子閱讀 677評(píng)論 0 0
  • Object C中創(chuàng)建線程的方法是什么险毁?如果在主線程中執(zhí)行代碼,方法是什么们童?如果想延時(shí)執(zhí)行代碼畔况、方法又是什么? 1...
    AlanGe閱讀 1,716評(píng)論 0 17
  • 1.單例模式 1.1 概念相關(guān) (1)單例模式 在程序運(yùn)行過(guò)程慧库,一個(gè)類只有一個(gè)實(shí)例 (2)使用場(chǎng)合 在整個(gè)應(yīng)用程序...
    怎樣m閱讀 251評(píng)論 0 0
  • 1.基本概念 2.pthread 3.NSThread (1)NSThread的基本使用 (2)設(shè)置線程的屬性 (...
    謝知行閱讀 114評(píng)論 0 0