<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          在開發(fā)中遇到的一些多線程問題

          共 3700字,需瀏覽 8分鐘

           ·

          2020-12-18 01:57

          作者 | boolchow?
          來源 | https://blog.boolchow.com/,點(diǎn)擊閱讀原文查看作者更多文章
          本文節(jié)選自作者 2018 年的《我所理解的 iOS 并發(fā)編程》,讀者小伙伴么在開發(fā)中遇到的并發(fā)問題,歡迎在留言區(qū)留言
          相對(duì)于 API 的使用和基本原理的了解,我認(rèn)為最重要的還是這一部分。畢竟我們還是要拿這些東西來開發(fā)的。并發(fā)編程中有很多坑,這里簡(jiǎn)單介紹一些。

          1. NSNotification 與多線程問題

          我們都知道,NSNotification 在哪個(gè)線程 post,最終就會(huì)在哪個(gè)線程執(zhí)行。如果我們不是在主線程 post 的,但是卻在主線程接收的,而且我們期望 selector 在主線程執(zhí)行。這時(shí)候我們需要注意下,在 selector 需要 dispatch 到主線程才可以。當(dāng)然你也可以使用 addObserverForName:object:queue:usingBlock: 來指定執(zhí)行 block 的 queue。
          @implementation BLPostNotification

          - (void)postNotification {
          dispatch_queue_t queue = dispatch_queue_create("com.bool.post.notification", DISPATCH_QUEUE_SERIAL);
          dispatch_async(queue, ^{
          // 從非主線程發(fā)送通知 (通知名字最好定義成一個(gè)常量)
          [[NSNotificationCenter defaultCenter] postNotificationName:@"downloadImage" object:nil];
          });
          }
          @end

          @implementation ImageViewController

          - (void)viewDidLoad {
          [super viewDidLoad];
          [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(show) name:@"downloadImage" object:nil];
          }

          - (void)showImage {
          // 需要 dispatch 到主線程更新 UI
          dispatch_async(dispatch_get_main_queue(), ^{
          // update UI
          });
          }
          @end

          2. NSTimer 與多線程問題

          使用 NSTimer 時(shí),在哪個(gè)線程生成的 timer,就在哪個(gè)線程銷毀,否則會(huì)有意想不到的結(jié)果。官方這樣描述的:
          However, for a repeating timer, you must invalidate the timer object yourself by calling its?invalidate?method. Calling this method requests the removal of the timer from the current run loop; as a result, you should always call the?invalidate?method from the same thread on which the timer was installed.
          @interface BLTimerTest ()
          @property (nonatomic, strong) dispatch_queue_t queue;
          @property (nonatomic, strong) NSTimer *timer;
          @end

          @implementation BLTimerTest
          - (instancetype)init {
          self = [super init];
          if (self) {
          _queue = dispatch_queue_create("com.bool.timer.test", DISPATCH_QUEUE_SERIAL);
          }
          return self;
          }

          - (void)installTimer {
          dispatch_async(self.queue, ^{
          self.timer = [NSTimer scheduledTimerWithTimeInterval:3.0f repeats:YES block:^(NSTimer * _Nonnull timer) {
          NSLog(@"test timer");
          }];
          });
          }

          - (void)clearTimer {
          dispatch_async(self.queue, ^{
          if ([self.timer isValid]) {
          [self.timer invalidate];
          self.timer = nil;
          }
          });
          }
          @end

          3. Dispatch Once 死鎖問題

          在開發(fā)中,我們經(jīng)常使用 dispatch_once,但是遞歸調(diào)用會(huì)造成死鎖。例如下面這樣:
          - (void)dispatchOnceTest {
          static dispatch_once_t onceToken;
          dispatch_once(&onceToken, ^{
          [self dispatchOnceTest];
          });
          }
          至于為什么會(huì)死鎖,上文介紹 Dispatch Once 的時(shí)候已經(jīng)說明了,這里就不多做介紹了。提醒一下使用的時(shí)候要注意,不要造成遞歸調(diào)用。

          4. Dispatch Group 問題

          在使用 dispatch_group 的時(shí)候,dispatch_group_enter(taskGroup) 和 dispatch_group_leave(taskGroup) 一定要成對(duì),否則也會(huì)出現(xiàn)崩潰。大多數(shù)情況下我們都會(huì)注意,但是有時(shí)候可能會(huì)疏忽。例如多層 for loop 時(shí) :
          - (void)testDispatchGroup {
          NSString *path = @"";
          NSFileManager *fileManager = [NSFileManager defaultManager];
          NSArray *folderList = [fileManager contentsOfDirectoryAtPath:path error:nil];
          dispatch_group_t taskGroup = dispatch_group_create();

          for (NSString *folderName in folderList) {
          dispatch_group_enter(taskGroup);
          NSString *folderPath = [@"path" stringByAppendingPathComponent:folderName];
          NSArray *fileList = [fileManager contentsOfDirectoryAtPath:folderPath error:nil];
          for (NSString *fileName in fileList) {
          dispatch_async(_queue, ^{
          // 異步任務(wù)
          dispatch_group_leave(taskGroup);
          });
          }
          }
          }
          上面的 dispatch_group_enter(taskGroup) 在第一層 for loop 中,而 dispatch_group_leave(taskGroup) 在第二層 for loop 中,兩者的關(guān)系是一對(duì)多,很容造成崩潰。有時(shí)候嵌套層級(jí)太多,很容易忽略這個(gè)問題。




          推薦閱讀
          如何把 if-else 重構(gòu)成高質(zhì)量代碼?

          如何閱讀代碼(八點(diǎn)要記牢)

          程序員必知的 7 種軟件架構(gòu)模式

          成為一流軟件開發(fā)者的 34 條建議

          用 Java 寫了一個(gè)類 QQ 界面聊天小項(xiàng)目,可在線聊天!


          點(diǎn)個(gè)『在看』支持下?
          就差您點(diǎn)一下了 ???
          瀏覽 31
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  摸胸上床做爱污污视频网站 | 毛片AV网址 | 人人天天爽 | 成人在线观看黄色 | 色网站操逼 |