В настоящее время я просматриваю диапазон дат и кэширую EKEvents
и EKReminders
, связанные с каждой датой. Проблема, с которой я столкнулся, заключается в том, что когда я получаю EKReminder
, API работает асинхронно. Проблема в том, что мне нужно получить доступ к содержимому этого потока из моей текущей очереди потока отправки. Я создал локальную переменную и __block'd ее, чтобы я мог назначить ей содержимое API async, а затем я завернул весь вызов fetch в вызов dispatch_sync, надеясь, что он задержит мою текущую очередь до тех пор, пока async не будет завершено, но этого не происходит. Как я могу остановить свой текущий поток, пока не будет завершен вызов асинхронного API?
Я предоставил два комментария ниже в коде, чтобы показать вам места, где мне нужно остановить выполнение кода и подождать.
- (void)setupCalendarCache {
// Dispatch the queueing of previous days to a background thread
dispatch_queue_t previousDaysCacheQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0);
dispatch_async(previousDaysCacheQueue, ^{
NSLog(@"Preparing to cache previous calendar days.");
int reverseYearsToCache = (HZ_NUMBER_OF_TOTAL_YEARS_TO_CACHE * 365) / 2;
DEDateUtility *dateUtility = [[DEDateUtility alloc] init];
NSCalendar *calendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
dispatch_apply(reverseYearsToCache, previousDaysCacheQueue, ^(size_t i) {
@synchronized (self.datesOnCalendar) {
NSLog(@"synchronizing calendar dates.");
// Setup start and end time for event & reminder fetching.
NSDate *date = [dateUtility adjustDate:self.currentDate byNumberOfDays:i-1];
NSLog(@"Working date %@", [date description]);
[self.datesOnCalendar insertObject:date atIndex:0];
// Start of the day
NSDateComponents *dateComponents = [[NSDateComponents alloc] init];
dateComponents.hour = 0;
dateComponents.minute = 0;
dateComponents.second = 0;
NSDate *startDate = [calendar dateByAddingComponents:dateComponents toDate:date options:0];
// End of the day
dateComponents.hour = 23;
dateComponents.minute = 59;
dateComponents.second = 59;
NSDate *endDate = [calendar dateByAddingComponents:dateComponents toDate:date options:0];
// Collections for the reminders and events fetched.
NSArray *events = [[NSArray alloc] init];
// Must be blocked so that the Block thread can access it even after this method is completed.
__block __strong NSArray *remindersList = [[NSArray alloc] init];
NSLog(@"Building predicates.");
// Predicates for fetching the reminders and events.
NSPredicate *fetchPredicateForEvents = [self.eventStore predicateForEventsWithStartDate:startDate endDate:endDate calendars:[self.eventStore calendarsForEntityType:EKEntityTypeEvent]];
NSPredicate *fetchPredicateForReminders = [self.eventStore predicateForIncompleteRemindersWithDueDateStarting:startDate ending:endDate calendars:[self.eventStore calendarsForEntityType:EKEntityTypeReminder]];
// Fetch the events matching the aforementioned NSPredicate.
events = [self.eventStore eventsMatchingPredicate:fetchPredicateForEvents];
// Don't store a nil array in the dictionary.
if (!events) {
events = [[NSArray alloc] init];
NSLog(@"No events found for this day.");
} else {
NSLog(@"Found %d events.", [events count]);
}
// ISSUE: Need to block execution until the following dispatch_sync is completed. How can I do this?
NSLog(@"Running reminders block.");
dispatch_sync(previousDaysCacheQueue, ^ {
// Fetch the reminders matching the aforementioned NSPredicate.
[self.eventStore fetchRemindersMatchingPredicate:fetchPredicateForReminders completion:^(NSArray *reminders) {
if (reminders ) {
remindersList = reminders;
NSLog(@"Found %d reminders (%d)", [remindersList count], [reminders count]);
return;
}
}];
});
NSLog(@"Building dictionaries for events and reminders.");
// CANT DO THIS. API async invocation is still taking place.
//Place the events and reminders in the dictionary
NSDictionary *eventsAndRemindersForDay = @{@"events": events, @"reminders" : remindersList};
[previousEventsAndReminders setObject:eventsAndRemindersForDay forKey:[date description]];
for (int index = 0; index < [remindersList count]; index++) {
EKReminder *reminder = remindersList[index];
NSLog(@"reminder: %@", reminder.title);
}
}
});
self.cachingStage += 1;
});
}