<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ThinkChat2.0新版上線,更智能更精彩,支持會話、畫圖、視頻、閱讀、搜索等,送10W Token,即刻開啟你的AI之旅 廣告
                **1.基本介紹:** (1) Grand Central Dispatch (GCD)是Apple開發的一個多核編程的較新的解決方法。在Mac OS X 10.6雪豹中首次推出,并在最近引入到了iOS4.0。 (2) GCD是一個替代諸如NSThread等技術的很高效和強大的技術。GCD完全可以處理諸如數據鎖定和資源泄漏等復雜的異步編程問題。 (3) 它是IOS多線程抽象層次最高的一層,下面還有前面2章節介紹的更加輕量級的Cocoa operations,和Thread。 **2.主要方法:** (1)創建一個隊列      dispatch_queue_t?queue =?dispatch_queue_create("LoadImage", NULL); ? ? ? ?其中,第一個參數是標識隊列的,第二個參數是用來定義隊列的參數(目前不支持,因此傳入NULL)。 (2)執行一個隊列(async--->異步,sync--->同步)      dispatch_async(queue, ^{ [self doSomething]; }); ? ? ? ? 其中,首先傳入之前創建的隊列,然后提供由隊列運行的代碼塊。 (3)聲明并執行一個隊列 (如果不需要保留要運行的隊列的引用)   dispatch_async(dispatch_queue_create ("LoadImage", NULL), ^{ [self doSomething]; }); (4)暫停一個隊列      dispatch_suspend(queue); (5)恢復一個隊列(如果暫停一個隊列不要忘記恢復) ? ? ? ?dispatch_resume(queue); (6)將代碼塊中的工作轉回到主線程(注意,dispatch_suspend (以及dispatch_resume)在主線程上不起作用)   dispatch_sync(dispatch_get_main_queue(), ^{ [self dismissLoginWindow]; }); **3.代碼示例** ~~~ #pragma mark - GCD(Grand Central Dispatch) - (void)GCD{ dispatch_queue_t queue = dispatch_queue_create("test", NULL); // 多一個a,異步 dispatch_async(queue, ^{ for (int i = 0; i < 100; i++) { NSLog(@"--多線程--%d",i); } // 判斷是否是在多線程運行環境 BOOL isMulti = [NSThread isMultiThreaded]; NSLog(@"%d",isMulti); if (isMulti) { NSLog(@"*********多線程***********"); } // 將代碼塊中的工作轉回到主線程 dispatch_sync(dispatch_get_main_queue(), ^{ // 判斷是否是在主線程運行環境 BOOL isMain = [NSThread isMainThread]; if (isMain) { NSLog(@"*********主線程**********"); } }); }); /* // 通過此方式,還是運行在當前線程 dispatch_sync(queue, ^{ // 主線程 }); */ for (int i = 0; i < 100; i++) { NSLog(@"--主線程--%d",i); } } ~~~ **4.加載網絡圖片(在多線程加載明顯比放在主線程加載快N多)** ~~~ #pragma mark - 給UIImageView寫一個類目 @interface UIImageView (WebCach) - (void)setImageWithURL:(NSURL *)url; @end #import "UIImageView+WebCach.h" @implementation UIImageView (WebCach) - (void)setImageWithURL:(NSURL *)url{ dispatch_queue_t queue = dispatch_queue_create("loadImage", NULL); dispatch_async(queue, ^{ NSData * data = [NSData dataWithContentsOfURL:url]; UIImage * image = [UIImage imageWithData:data]; // 加載UI的操作,一般放在主線程進行 dispatch_async(dispatch_get_main_queue(), ^{ self.image = image; }); }); } @end - (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view. UIImageView * imageView = [[UIImageView alloc]initWithFrame:CGRectMake(100, 100, 100, 100)]; [imageView setImageWithURL:[NSURL URLWithString:@"http://www.baidu.com/img/bdlogo.gif"]]; [self.view addSubview:imageView]; } ~~~ **5.最后,引用別人博客對幾個方法的介紹** @[dispatch對象](http://blog.csdn.net/lengshengren/article/details/12905747) ~~~ 原文地址 http://www.cnblogs.com/sunfrog/p/3243230.html 談起iOS的dispatch(正式稱謂是Grand Central Dispatch或GCD),不得不說這又是iOS(包括MacOSX)平臺的創新,優缺點這里不討論,只有當你使用時才能真正體會到。我們說dispatch函數的主要目的是實現多任務并發代碼,那么要理解dispatch函數,先來了解dispatch對象的定義。 dispatch對象類型的部分定義,主要使用C語言的宏定義: <os/object.h>文件: #define OS_OBJECT_CLASS(name) OS_##name #define OS_OBJECT_DECL(name, ...) \ @protocol OS_OBJECT_CLASS(name) __VA_ARGS__ \ @end \ typedef NSObject<OS_OBJECT_CLASS(name)> *name##_t #define OS_OBJECT_DECL_SUBCLASS(name, super) \ OS_OBJECT_DECL(name, <OS_OBJECT_CLASS(super)>) <dispatch/object.h>文件: #define DISPATCH_DECL(name) OS_OBJECT_DECL_SUBCLASS(name, dispatch_object) #define DISPATCH_GLOBAL_OBJECT(type, object) ((OS_OBJECT_BRIDGE type)&(object)) OS_OBJECT_DECL(dispatch_object); //定義dispatch_object_t <dispatch/queue.h>文件(dispatch隊列類定義,其它dispatch對象類似): DISPATCH_DECL(dispatch_queue); //定義dispatch_queue_t 可以通過Xcode預編譯后可以看到最終結果,最終定義的都是NSObject類,雖然它們之間沒用直接繼承關系,但都實現OS_dispatch_object接口,這樣dispatch_queue_t對象也同樣是dispatch_object_t的對象了。下面就是預編譯dispatch_object_t和dispatch_queue_t的結果: @protocol OS_dispatch_object @end typedef NSObject<OS_dispatch_object> *dispatch_object_t; @protocol OS_dispatch_queue <OS_dispatch_object> @end typedef NSObject<OS_dispatch_queue> *dispatch_queue_t; 由于dispatch api接口定義成C函數的形式,dispatch的對象都是由C函數形式的廠方法得到(不能繼承dispatch類,不用alloc),這樣做隱藏dispatch對象的具體形態,把注意力放在如何調用dispatch api上。 從上面dispatch對象宏定義可以看到dispatch對象類的名稱一般為dispatch_xyz_t(嚴格來講是對象指針),它們都可以看成dispatch_object_t的子類(對象指針),所以使用dispatch對象時套用這個概念就行。 有關dispatch對象的基本接口如下: void dispatch_retain(dispatch_object_t object); //替代dispatch對象常規的retain來持有對象,但ARC編程中不再允許 void dispatch_release(dispatch_object_t object); //替代dispatch對象常規的release來釋放對象,同樣ARC編程中不再允許 void dispatch_set_context(dispatch_object_t object, void *context); //給dispatch對象綁定特定數據對象(類似線程的TLS數據),會被傳給dispatch對象的finalizer函數 void *dispatch_get_context(dispatch_object_t object); //返回dispatch對象綁定的數據對象指針 void dispatch_set_finalizer_f(dispatch_object_t object, dispatch_function_t finalizer); //設置dispatch對象的finalizer函數,當該對象釋放時會調用finalizer,部分代碼解釋如何使用這個函數(ARC模式): dispatch_object_t dispatchObject = ...; void *context = ...; dispatch_set_context(dispatchObject, context); dispatch_set_finalizer_f(dispatchObject, finalizer); ...... dispatchObject = nil; //dispatchObject被釋放,這時調用finalizer函數 ...... void finalizer(void *context) {   //處理或釋放context相關資源 } dispatch對象的另外兩個接口是: void dispatch_resume(dispatch_object_t object); //激活(啟動)在dispatch對象上的block調用,可以運行多個block void dispatch_suspend(dispatch_object_t object); //掛起(暫停)在dispatch對象上的block調用,已經運行的block不會停止 一般這兩個函數的調用必須成對,否則運行會出現異常。 至此你是否發現這兩個函數有些與眾不同呢?好像從來沒有這么使用對象的,啟動對象--暫停對象,呵呵。這正是理解dispatch對象的關鍵所在。dispatch對象其實是抽象的任務,把動態的任務變成對象來管理。任務是動態的,不存在繼承關系,這就是為什么GCD沒有提供靜態繼承dispatch對象類的方式。如果能這樣理解,那么在使用dispatch函數時就能夠更靈活地去編寫代碼,實現各種并發的多任務代碼。 ~~~ @[dispatch隊列](http://blog.csdn.net/lengshengren/article/details/12905787) ~~~ GCD編程的核心就是dispatch隊列,dispatch block的執行最終都會放進某個隊列中去進行,它類似NSOperationQueue但更復雜也更強大,并且可以嵌套使用。所以說,結合block實現的GCD,把函數閉包(Closure)的特性發揮得淋漓盡致。 dispatch隊列的生成可以有這幾種方式: 1. dispatch_queue_t queue = dispatch_queue_create("com.dispatch.serial", DISPATCH_QUEUE_SERIAL); //生成一個串行隊列,隊列中的block按照先進先出(FIFO)的順序去執行,實際上為單線程執行。第一個參數是隊列的名稱,在調試程序時會非常有用,所有盡量不要重名了。 2. dispatch_queue_t queue = dispatch_queue_create("com.dispatch.concurrent", DISPATCH_QUEUE_CONCURRENT); //生成一個并發執行隊列,block被分發到多個線程去執行 3. dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); //獲得程序進程缺省產生的并發隊列,可設定優先級來選擇高、中、低三個優先級隊列。由于是系統默認生成的,所以無法調用dispatch_resume()和dispatch_suspend()來控制執行繼續或中斷。需要注意的是,三個隊列不代表三個線程,可能會有更多的線程。并發隊列可以根據實際情況來自動產生合理的線程數,也可理解為dispatch隊列實現了一個線程池的管理,對于程序邏輯是透明的。 官網文檔解釋說共有三個并發隊列,但實際還有一個更低優先級的隊列,設置優先級為DISPATCH_QUEUE_PRIORITY_BACKGROUND。Xcode調試時可以觀察到正在使用的各個dispatch隊列。 4. dispatch_queue_t queue = dispatch_get_main_queue(); //獲得主線程的dispatch隊列,實際是一個串行隊列。同樣無法控制主線程dispatch隊列的執行繼續或中斷。 接下來我們可以使用dispatch_async或dispatch_sync函數來加載需要運行的block。 dispatch_async(queue, ^{   //block具體代碼 }); //異步執行block,函數立即返回 dispatch_sync(queue, ^{   //block具體代碼 }); //同步執行block,函數不返回,一直等到block執行完畢。編譯器會根據實際情況優化代碼,所以有時候你會發現block其實還在當前線程上執行,并沒用產生新線程。 實際編程經驗告訴我們,盡可能避免使用dispatch_sync,嵌套使用時還容易引起程序死鎖。 如果queue1是一個串行隊列的話,這段代碼立即產生死鎖: dispatch_sync(queue1, ^{ dispatch_sync(queue1, ^{     ......   });   ......  }); 不妨思考下,為什么下面代碼也肯定死鎖: dispatch_sync(dispatch_get_main_queue(), ^{   ...... }); 那實際運用中,一般可以用dispatch這樣來寫,常見的網絡請求數據多線程執行模型: dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{   //子線程中開始網絡請求數據   //更新數據模型   dispatch_sync(dispatch_get_main_queue(), ^{     //在主線程中更新UI代碼   }); }); 程序的后臺運行和UI更新代碼緊湊,代碼邏輯一目了然。 dispatch隊列是線程安全的,可以利用串行隊列實現鎖的功能。比如多線程寫同一數據庫,需要保持寫入的順序和每次寫入的完整性,簡單地利用串行隊列即可實現: dispatch_queue_t queue1 = dispatch_queue_create("com.dispatch.writedb", DISPATCH_QUEUE_SERIAL); - (void)writeDB:(NSData *)data {   dispatch_async(queue1, ^{     //write database   }); } 下一次調用writeDB:必須等到上次調用完成后才能進行,保證writeDB:方法是線程安全的。 dispatch隊列還實現其它一些常用函數,包括: void dispatch_apply(size_t iterations, dispatch_queue_t queue, void (^block)(size_t)); //重復執行block,需要注意的是這個方法是同步返回,也就是說等到所有block執行完畢才返回,如需異步返回則嵌套在dispatch_async中來使用。多個block的運行是否并發或串行執行也依賴queue的是否并發或串行。 void dispatch_barrier_async(dispatch_queue_t queue, dispatch_block_t block); //這個函數可以設置同步執行的block,它會等到在它加入隊列之前的block執行完畢后,才開始執行。在它之后加入隊列的block,則等到這個block執行完畢后才開始執行。 void dispatch_barrier_sync(dispatch_queue_t queue, dispatch_block_t block); //同上,除了它是同步返回函數 void dispatch_after(dispatch_time_t when, dispatch_queue_t queue, dispatch_block_t block); //延遲執行block 最后再來看看dispatch隊列的一個很有特色的函數: void dispatch_set_target_queue(dispatch_object_t object, dispatch_queue_t queue); 它會把需要執行的任務對象指定到不同的隊列中去處理,這個任務對象可以是dispatch隊列,也可以是dispatch源(以后博文會介紹)。而且這個過程可以是動態的,可以實現隊列的動態調度管理等等。比如說有兩個隊列dispatchA和dispatchB,這時把dispatchA指派到dispatchB: dispatch_set_target_queue(dispatchA, dispatchB); 那么dispatchA上還未運行的block會在dispatchB上運行。這時如果暫停dispatchA運行: dispatch_suspend(dispatchA); 則只會暫停dispatchA上原來的block的執行,dispatchB的block則不受影響。而如果暫停dispatchB的運行,則會暫停dispatchA的運行。 這里只簡單舉個例子,說明dispatch隊列運行的靈活性,在實際應用中你會逐步發掘出它的潛力。 dispatch隊列不支持cancel(取消),沒有實現dispatch_cancel()函數,不像NSOperationQueue,不得不說這是個小小的缺憾。 ~~~ @[dispatch源](http://blog.csdn.net/lengshengren/article/details/12905811) ~~~ 原文地址 http://www.cnblogs.com/sunfrog/p/3243230.html dispatch源(dispatch source)和RunLoop源概念上有些類似的地方,而且使用起來更簡單。要很好地理解dispatch源,其實把它看成一種特別的生產消費模式。dispatch源好比生產的數據,當有新數據時,會自動在dispatch指定的隊列(即消費隊列)上運行相應地block,生產和消費同步是dispatch源會自動管理的。 dispatch源的使用基本為以下步驟: 1. dispatch_source_t source = dispatch_source_create(dispatch_source_type, handler, mask, dispatch_queue); //創建dispatch源,這里使用加法來合并dispatch源數據,最后一個參數是指定dispatch隊列 2. dispatch_source_set_event_handler(source, ^{ //設置響應dispatch源事件的block,在dispatch源指定的隊列上運行   //可以通過dispatch_source_get_data(source)來得到dispatch源數據 }); 3. dispatch_resume(source); //dispatch源創建后處于suspend狀態,所以需要啟動dispatch源 4. dispatch_source_merge_data(source, value); //合并dispatch源數據,在dispatch源的block中,dispatch_source_get_data(source)就會得到value。 是不是很簡單?而且完全不必編寫同步的代碼。比如網絡請求數據的模式,就可以這樣來寫: dispatch_source_t source = dispatch_source_create(DISPATCH_SOURCE_TYPE_DATA_ADD, 0, 0, dispatch_get_global_queue(0, 0)); dispatch_source_set_event_handler(source, ^{ dispatch_sync(dispatch_get_main_queue(), ^{     //更新UI }); }); dispatch_resume(source); dispatch_async(dispatch_get_global_queue(0, 0), ^{    //網絡請求 dispatch_source_merge_data(source, 1); //通知隊列 }); dispatch源還支持其它一些系統源,包括定時器、監控文件的讀寫、監控文件系統、監控信號或進程等,基本上調用的方式原理和上面相同,只是有可能是系統自動觸發事件。比如dispatch定時器: dispatch_source_t timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue); dispatch_source_set_timer(timer, dispatch_walltime(NULL, 0), 10*NSEC_PER_SEC, 1*NSEC_PER_SEC); //每10秒觸發timer,誤差1秒 dispatch_source_set_event_handler(timer, ^{   //定時處理 }); dispatch_resume(timer); 其它情況的dispatch源就不再一一舉例,可參看官網有具體文檔: https://developer.apple.com/library/ios/documentation/General/Conceptual/ConcurrencyProgrammingGuide/GCDWorkQueues/GCDWorkQueues.html#//apple_ref/doc/uid/TP40008091-CH103-SW1 最后,dispatch源的其它一些函數大致羅列如下: uintptr_t dispatch_source_get_handle(dispatch_source_t source); //得到dispatch源創建,即調用dispatch_source_create的第二個參數 unsignedlong dispatch_source_get_mask(dispatch_source_t source); //得到dispatch源創建,即調用dispatch_source_create的第三個參數 void dispatch_source_cancel(dispatch_source_t source); //取消dispatch源的事件處理--即不再調用block。如果調用dispatch_suspend只是暫停dispatch源。 long dispatch_source_testcancel(dispatch_source_t source); //檢測是否dispatch源被取消,如果返回非0值則表明dispatch源已經被取消 void dispatch_source_set_cancel_handler(dispatch_source_t source, dispatch_block_t cancel_handler); //dispatch源取消時調用的block,一般用于關閉文件或socket等,釋放相關資源 void dispatch_source_set_registration_handler(dispatch_source_t source, dispatch_block_t registration_handler); //可用于設置dispatch源啟動時調用block,調用完成后即釋放這個block。也可在dispatch源運行當中隨時調用這個函數。 ~~~ @[dispatch同步](http://blog.csdn.net/lengshengren/article/details/12905821) ~~~ 原文地址 http://www.cnblogs.com/sunfrog/p/3243230.html GCD提供兩種方式支持dispatch隊列同步,即dispatch組和信號量。 一、dispatch組(dispatch group) 1. 創建dispatch組 dispatch_group_t group = dispatch_group_create(); 2. 啟動dispatch隊列中的block關聯到group中 dispatch_group_async(group, queue, ^{   // 。。。 }); 3. 等待group關聯的block執行完畢,也可以設置超時參數 dispatch_group_wait(group, DISPATCH_TIME_FOREVER); 4. 為group設置通知一個block,當group關聯的block執行完畢后,就調用這個block。類似dispatch_barrier_async。 dispatch_group_notify(group, queue, ^{   // 。。。 }); 5. 手動管理group關聯的block的運行狀態(或計數),進入和退出group次數必須匹配 dispatch_group_enter(group); dispatch_group_leave(group); 所以下面的兩種調用其實是等價的, A) dispatch_group_async(group, queue, ^{   // 。。。 }); B) dispatch_group_enter(group); dispatch_async(queue, ^{   //。。。   dispatch_group_leave(group); }); 所以,可以利用dispatch_group_enter、 dispatch_group_leave和dispatch_group_wait來實現同步,具體例子:http://stackoverflow.com/questions/10643797/wait-until-multiple-operations-executed-including-completion-block-afnetworki/10644282#10644282。 二、dispatch信號量(dispatch semaphore) 1. 創建信號量,可以設置信號量的資源數。0表示沒有資源,調用dispatch_semaphore_wait會立即等待。 dispatch_semaphore_t semaphore = dispatch_semaphore_create(0); 2. 等待信號,可以設置超時參數。該函數返回0表示得到通知,非0表示超時。 dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER); 3. 通知信號,如果等待線程被喚醒則返回非0,否則返回0。 dispatch_semaphore_signal(semaphore); 最后,還是回到生成消費者的例子,使用dispatch信號量是如何實現同步: dispatch_semaphore_t sem = dispatch_semaphore_create(0); dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ //消費者隊列 while (condition) {     if (dispatch_semaphore_wait(sem, dispatch_time(DISPATCH_TIME_NOW, 10*NSEC_PER_SEC))) //等待10秒       continue;     //得到數據   } }); dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ //生產者隊列 while (condition) {     if (!dispatch_semaphore_signal(sem))     {       sleep(1); //wait for a while       continue;     }     //通知成功   } }); ~~~
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看