0

我同時運行兩個不同的dispatch queues,循環遍歷365次迭代並實例化一個對象。該循環將該對象添加到NSNotificationCenter,然後該對象在完成事件存儲​​區異步代碼塊後發佈通知。我的問題是,我應該在調試器中收到730條消息,但我不知道。每次運行應用程序時,我都會收到不同數量的消息,從513到630.NSNotificationCenter observer收到不同數量的每次運行的通知

是否有任何理由解釋這種情況?

這是我執行循環的代碼,並將對象添加到Notification Center。我創建了一個HZCalendarDay的實例,我將它添加到一個不可變數組中。

- (id)init { 
    self = [super init]; 

    if (self) { 
     // Alloc/Init instance variables. 
     previousDays = [[NSMutableArray alloc] init]; 
     futureDays = [[NSMutableArray alloc] init]; 
     self.datesOnCalendar = [[NSMutableArray alloc] init]; 
     self.stateOfCalendarCache = StateOfEventStoreCache_CachingRequired; 
     self.currentDay = [[HZCalendarDay alloc] init]; 

     // Setup our event store security access. 
     [self setupEventStore]; 

     DEDateUtility *dateUtility = [[DEDateUtility alloc] init]; 
     NSDate *today = [dateUtility normalizedDateWithDate:[NSDate date]]; 
     HZCalendarDay *date = [[HZCalendarDay alloc] initOnDate:today withEventStore:self.eventStore]; 
     [self.datesOnCalendar addObject:date]; 
     self.currentDay = date; 

     // Before we start caching, we need to setup the KVO so we can compile the 
     // completed caches, since both previous and future days are cached separately. 


     // Start caching previous days. 
     dispatch_queue_t previousDaysCacheQueue = dispatch_queue_create("previousDaysCacheQueue", NULL); 
     dispatch_async(previousDaysCacheQueue,^{ 
      int numberOfDays = (HZ_NUMBER_OF_TOTAL_YEARS_TO_CACHE * 365)/2; 
      for (int count = 1; count < numberOfDays; count++) { 
       NSDate *previousDate = [dateUtility adjustDate:today byNumberOfDays:-count]; 
       HZCalendarDay *calendarDay = [[HZCalendarDay alloc] initOnDate:previousDate withEventStore:self.eventStore]; 
       [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(completeCaching:) name:HZ_KVO_CALENDAR_CACHE_NOTIFICATION object:calendarDay]; 

       @synchronized (self.datesOnCalendar) { 
        [self.datesOnCalendar insertObject:calendarDay atIndex:0]; 
       } 
      } 
     }); 

     // Start caching future days. 
     dispatch_queue_t futureDaysCacheQueue = dispatch_queue_create("futureDaysCacheQueue", NULL); 
     dispatch_async(futureDaysCacheQueue,^{ 
      int numberOfDays = (HZ_NUMBER_OF_TOTAL_YEARS_TO_CACHE * 365)/2; 
      for (int count = 1; count < numberOfDays; count++) { 
       NSDate *futureDate = [dateUtility adjustDate:today byNumberOfDays:count]; 
       HZCalendarDay *calendarDay = [[HZCalendarDay alloc] initOnDate:futureDate withEventStore:self.eventStore]; 
       [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(completeCaching:) name:HZ_KVO_CALENDAR_CACHE_NOTIFICATION object:calendarDay]; 

       @synchronized (self.datesOnCalendar) { 
        [self.datesOnCalendar addObject:calendarDay]; 
       } 
      }; 
     }); 
    } 

    return self; 
} 

在同一個班級,我有我的NSNotificationCenter職位的方法,以及cacheStageNSLogs當前值的制定者。它最終應該等於730,但它永遠不會那麼高。

- (void)setCachingStage:(NSInteger)cachingStage { 
    _cachingStage = cachingStage; 
    NSLog(@ 
      "Cache Stage: %d", _cachingStage); 

    if (_cachingStage == (HZ_NUMBER_OF_TOTAL_YEARS_TO_CACHE*365)) { 
     self.stateOfCalendarCache = StateOfEventStoreCache_CachingComplete; 
     NSLog(@"Caching completed."); 
    } 
} 

- (void)completeCaching:(NSNotification *)notification { 
    [[NSNotificationCenter defaultCenter] removeObserver:self name:HZ_KVO_CALENDAR_CACHE_NOTIFICATION object:(HZCalendarDay *)notification.object]; 
    self.cachingStage++; 
} 

這是HZCalendarDay初始化,即然後獲取事件和提醒的緩存。一旦事件和提醒被設置,它就會PostsNotificationCenter

- (void)setCacheStage:(NSInteger)cacheStage { 
    _cacheStage = cacheStage; 

    if (_cacheStage == 2) { 
     [[NSNotificationCenter defaultCenter] postNotificationName:HZ_KVO_CALENDAR_CACHE_NOTIFICATION object:self]; 
    } 
} 

- (id)initOnDate:(NSDate *)date withEventStore:(EKEventStore *)eventStore { 
    self = [super init]; 

    if (self) { 
     self.events = [[NSArray alloc] init]; 
     self.reminders = [[NSArray alloc] init]; 
     self.date = date; 
     self.eventStore = eventStore; 

     [self fetchAllEvents]; 
     [self fetchAllReminders]; 
    } 

    return self; 
} 

- (void)fetchAllEvents { 
    NSPredicate *fetchPredicateForEvents = [self.eventStore predicateForEventsWithStartDate:[self startTime] endDate:[self endTime] calendars:[self.eventStore calendarsForEntityType:EKEntityTypeEvent]]; 
    self.events = [self.eventStore eventsMatchingPredicate:fetchPredicateForEvents]; 

    // Don't store a nil array in the dictionary. 
    if (!self.events) { 
     self.events = [[NSArray alloc] init]; 
    } 

    self.cacheStage++; 
} 

- (void)fetchAllReminders { 
    NSPredicate *fetchPredicateForReminders = [self.eventStore predicateForIncompleteRemindersWithDueDateStarting:[self startTime] ending:[self endTime] calendars:[self.eventStore calendarsForEntityType:EKEntityTypeReminder]]; 
    [self.eventStore fetchRemindersMatchingPredicate:fetchPredicateForReminders completion:^(NSArray *reminders) { 
     @synchronized (self.reminders) { 
      self.reminders = reminders; 
     } 
     self.cacheStage++; 

    }]; 
} 

有人可以向我解釋什麼可能會出錯嗎?這與多線程相關嗎?如果是這樣,有沒有更好的方法讓我讓實例化對象的類知道對象已緩存了事件存儲庫提醒?這個類是我的UITableView的數據源,所以我需要緩存提醒,並且讓我的數據源知道緩存已經完成。這允許我的UI在高速緩存發生時在其上顯示「刷新」或加載指示符。

+0

快速注意,如果我更換calendarDay對象作爲一個零參數的通知中心,然後通知中心修建垃圾與成千上萬的NSLog的控制檯。我不確定爲什麼NSNotificationCenter沒有按照預期的方式工作。 –

回答

0

您正在執行的方式cachingStage不是線程安全的。請注意,僅僅是包裝在@synchronizedcachingStage/setCachingStage:執行不在這種情況下足夠了,因爲你這樣做:

self.cachingStage++; 

...這實際上是等價的:

NSInteger foo = self.cacheStage; foo++; self.cacheStage = foo; 

當你有兩個線程& b執行此操作,會出現以下情況:

  1. 線程A讀取電流值,x,輸入foo
  2. 線程A被搶佔並進入睡眠狀態。
  3. 線程B讀取當前值,x,爲foo,增加foox + 1,並將其寫回cachingStage,做了一堆其他的東西,並最終捷足先登。
  4. 線程A重新開始,將它的foo增加到x + 1,並將該值寫回cachingStage

此時,您希望cachingStagex + 2,但事實並非如此。這是x + 1。如果你仔細想想,這完全可以解釋爲什麼你的價值永遠不會像你想象的那麼高。您需要明確保護可以從多個線程操縱的任何數據/狀態。取而代之的setCachingStage:,在這種情況下,你可能要像incrementCachingStage的方法,你可能再實現這樣的:

- (void) incrementCachingStage { 
    @synchronized(self) { 
     _cachingStage++; 
     NSLog(@"Cache Stage: %d", _cachingStage); 

     if (_cachingStage == (HZ_NUMBER_OF_TOTAL_YEARS_TO_CACHE*365)) { 
      self.stateOfCalendarCache = StateOfEventStoreCache_CachingComplete; 
      NSLog(@"Caching completed."); 
     } 
    } 
} 

這只是一個數據,雖然,你有一堆在這裏,一些/所有這些都可能需要進行線程安全。

相關問題