GCD

/*------------------------------ GCD使用 1.隊列和任務------------------------------------------*/程序員

重點:1."串行隊列"? "併發隊列"? 2.block?面試

{設計模式

    1.GCD(Grand Central Dispatch) ---- '牛逼的中樞調度器'!安全

    // C語言框架 / 自動管理線程的生命週期(建立/釋放)網絡

    

    推出GCD的目的:取代NSThread!併發

    

    "多核""並行"運算提出的解決方案!框架

    

    優勢:異步

    <1> GCD 可以自動利用更多的CPU的核數(雙核/四核)!async

    <2> GCD 會自動管理線程的生命週期.函數

    

    程序員只須要告訴 GCD 想要執行的任務(代碼)!

    

    2.GCD中的兩個核心概念:

    

    "任務":

        想要作的事情/執行什麼操做.

        GCD 中的任務定義在block.

        void (^myBlock)() = ^{

            // 想要作的事情/任務

        }

    

    "隊列":

        用來'存放'任務!

    

    隊列 != 線程!

    隊列中存放的任務最後都要由線程來執行!

    

    隊列的原則:先進先出,後進後出(FIFO/ First In First Out)!

 

    隊列的類型:

    <1> '串行'隊列:(Serial Dispatch Queue)

    存放按順序執行的任務!(一個任務執行完畢,再執行下一個任務)!

    

    // 建立一個串行隊列

    dispatch_queue_t serialQueue = dispatch_queue_create("serial", DISPATCH_QUEUE_SERIAL);

    

    <2> '併發'隊列:(Concurrent Dispatch Queue)

    存放想要同時(併發)執行的任務!

    

    // 建立一個併發隊列

    dispatch_queue_t concurrentQueue = dispatch_queue_create("concurrent",DISPATCH_QUEUE_CONCURRENT);

    

    注意兩個很是經常使用的特殊隊列:

    

    <1> 主隊列: // UI 操做放在主隊列中執行!

        跟主線程相關聯的隊列!

        主隊列是 GCD 自帶的一種特殊的串行隊列!

        主隊列中的任務都會在主線程中執行!

    //獲取主隊列

    dispatch_queue_t mainQueue = dispatch_get_main_queue();

    

    <2> 全局併發隊列: // 通常狀況下,併發任務均可以放在全局併發隊列中!

    //獲取全局併發隊列

    dispatch_queue_t globalQueue = dispatch_get_global_queue(0, 0);

}

/*-----------------------------------  GCD使用 2.執行任務 -------------------------------------*/

重點:1."同步"函數!"異步"函數! 2.容易混淆的四個概念: '串行' ,'併發' ,"同步" ,"異步"之間的區別?

{

    問題:串行隊列中的任務一定按順序執行嗎?併發隊列中的任務一定同時執行嗎?

    

    GCD中有兩個用來執行任務的函數:

    

    '同步'執行任務:

    dispatch_sync(<#dispatch_queue_t queue#>, <#^(void)block#>)

    

    '異步'執行任務:

    dispatch_async(dispatch_queue_t queue, <#^(void)block#>)

 

    // <#dispatch_queue_t queue#> :隊列

    // <#^(void)block#>:任務

    

    "同步""異步"的區別:

    "同步": 只能在'當前'線程中執行任務,不具有開啓新線程的能力.

    "異步": 能夠在''的線程中執行任務,具有開啓新線程的能力.

    

    GCD 使用有兩個步驟:

    <1> 將任務添加到隊列中;

    <2> 選擇同步仍是異步的方式執行任務.

    

    注意:四個容易混淆的術語:

    '串行' ,'併發' ,"同步" ,"異步".

}

/*-------------------------------  GCD使用 3.各類隊列的執行效果 ---------------------------------*/

重點:1.掌握兩個經常使用的組合!

{

    常見的組合(掌握)

    1> dispatch_async + 全局併發隊列 (能夠開啓多條線程)

    2> dispatch_async + 本身建立的串行隊列 (開啓一條線程)

    

    只有'異步'執行"併發"隊列,才能夠開啓多條線程.

    

    注意:

    在主線程中同步執行主隊列中的任務,會形成'主線程''主隊列'相互等待,卡住主線程!

}

/*-------------------------------  GCD使用 4.線程間通訊 ---------------------------------------*/

重點:1.從子線程回到主線程(經典用法)! 2.兩個注意點.

{

    1.經典用法(子線程下載(耗時操做),主線程刷新UI):

    dispatch_async(dispatch_get_global_queue(0, 0), ^{

        

                       // 執行耗時的異步操做...

        

                       dispatch_async(dispatch_get_main_queue(), ^{

                           

                           // 回到主線程,執行UI刷新操做

                           

                       });

                   });

 

    2.注意:

    <1> 須要設置按鈕的image,建議先把按鈕類型改成custom,才能保證設置成功

    <2> 屬性名不能以new開頭

}

/*-------------------------------  GCD使用 5.延時執行  -----------------------------------------*/

重點:1.iOS常見的兩種延時執行方式

{

    iOS中的延時執行方式:

    // 定製好延時任務後,不會阻塞當前線程.

    

    <1> 調用 NSObject 方法:

    [self performSelector:@selector(run) withObject:nil afterDelay:2.0];

    // 2秒後再調用selfrun方法

    

    <2> GCD 函數實現延時執行:

    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{

        // 2秒後執行這裏的代碼... 在哪一個線程執行,跟隊列類型有關

    });

    

    注意:

    不要使用sleep,會阻塞當前線程.

}

/*-------------------------------  GCD使用 6.隊列組   ------------------------------------------*/

重點:1.瞭解隊列組的使用方法.

{

    項目需求:

    首先:分別異步執行兩個耗時操做;

    其次:等兩次耗時操做都執行完畢後,再回到主線程執行操做.

    

    使用隊列組(dispatch_group_t)快速,高效的實現上述需求.

    

    dispatch_group_t group = dispatch_group_create(); // 隊列組

    dispatch_queue_t queue = dispatch_get_global_queue(0, 0); // 全局併發隊列

    

    dispatch_group_async(group, queue, ^{         // 異步執行操做1

        // longTime1

    });

    

    dispatch_group_async(group, queue, ^{         // 異步執行操做2

        // longTime2

    });

    

    dispatch_group_notify(group, dispatch_get_main_queue(), ^{     // 在主線程刷新數據

        // reload Data

    });

}

/*-------------------------------  GCD使用 7.一次性代碼 ---------------------------------------*/

重點:1.掌握一次性代碼的實現.

{

    一次性代碼:

    static dispatch_once_t onceToken;

    dispatch_once(&onceToken, ^{

        // 只執行一次的代碼(這裏面默認是線程安全的).

    });

}

/*--------------------------------------  補充: 單例設計模式 -----------------------------------*/

重點:1.掌握單例!

{

    1.單例簡介:

    

    做用:

        保證程序在運行過程當中,一個類只有一個實例對象.這個實例對象容易被外界訪問!

        控制實例對象個數(只有一個),節約系統資源.

    

    使用場合:

        在整個應用程序中,共享一份資源(這份資源只須要建立初始化一次).

    

    舉例:

        打印機/視圖窗口/一些網絡工具類等等

    

    // 懶漢式: 用到的時候再加載.

    // 餓漢式: 只要程序運行就加載. // 不須要掌握,也不要這麼寫!

    // 掌握懶漢式.

    

    2.單例實現:(兩種方式:互斥鎖(@synchronized(self))和一次性代碼(dispatch_once));

    

    2.1互斥鎖 @synchronized(self):

    

    <1>. .m 文件中保留一個全局的 static 的實例.

    

        static id _instance;

    

    <2>.重寫若干方法(allocWithZone: copyWithZone:)並提供一個類方法讓外界訪問惟一的實例.

    

    //(1)重寫 allocWithZone:方法,在這裏建立惟一的實例(注意線程安全). //alloc 內部都會調用這個方法.

        +(instancetype)allocWithZone:(struct _NSZone *)zone {

            if (_instance == nil) { // 防止頻繁加鎖

                @synchronized(self) {

                    if (_instance == nil) { // 防止建立屢次

                        _instance = [super allocWithZone:zone];

                    }

                }

            }

            return _instance;

        }

    

    //(2)重寫 copyWithZone:方法.

        +(id)copyWithZone:(struct _NSZone *)zone

        {

            return _instance;

        }

    //(3)提供1個類方法讓外界訪問惟一的實例

        +(instancetype)shareSingleton

        {

            if (!_instance) { // 防止頻繁加鎖

                @synchronized(self){

                    if (!_instance) { // 防止建立屢次

                        _instance = [[self alloc] init];

                    }

                }

            }

            return _instance;

        }

    

    2.2 一次性代碼(dispatch_once):

    <1>. .m 文件中保留一個全局的 static 的實例.

    

    static id _instance;

    

    <2>.重寫若干方法(allocWithZone: copyWithZone:)並提供一個類方法讓外界訪問惟一的實例.

    

    //(1)重寫 allocWithZone:方法,在這裏建立惟一的實例(注意線程安全).

    + (id)allocWithZone:(struct _NSZone *)zone

    {

        static dispatch_once_t onceToken;

        dispatch_once(&onceToken, ^{

            _instace = [super allocWithZone:zone];

        });

        return _instace;

    }

    

    //(2)重寫 copyWithZone:方法.

    +(id)copyWithZone:(struct _NSZone *)zone

    {

        return _instance;

    }

    //(3)提供1個類方法讓外界訪問惟一的實例

    + (instancetype)shareSingleton

    {

        static dispatch_once_t onceToken;

        dispatch_once(&onceToken, ^{

            _instace = [[self alloc] init];

        });

        return _instace;

    }

 

    注意: ARC MRC 中單例的實現方式略有不一樣. MRC 下單例的實現比 ARC 多了幾個內存管理的方法:

    

    MRC 中增長以下方法的實現:

    - (instancetype)retain { return self; }

    - (NSUInteger)retainCount { return 1; }

    - (oneway void)release {}

    - (instancetype)autorelease { return self; }

    

    3.判斷當前環境(ARC/MRC)

    

#if __has_feature(objc_arc)

    // ARC

#else

    // MRC

#endif

    

    4.注意兩個方法:

    // 面試問題:兩個方法的區別?

    <1> +(void)load;

    // 當類加載到OC運行時環境(內存)中的時候,就會調用一次(一個類只會加載一次).

    // 程序一啓動就會調用.

    // 程序運行過程當中,只會調用1.

    <2> +(void)initialize;

    // 當第一次使用這個類的時候(好比調用了類的某個方法)纔會調用.

    // 並不是程序一啓動就會調用.

}

相關文章
相關標籤/搜索
本站公眾號
   歡迎關注本站公眾號,獲取更多信息