Когда я создаю NSPredicate через EKEventStore predicateForRemindersInCalendars; и передать его в EKEventStore fetchRemindersMatchingPredicate: завершение:^Я могу пропустить массив напоминаний, предоставляемый блоком кода завершения, но когда я пытаюсь сохранить ссылку на массив напоминаний или создать копию массива в локальной переменной или экземпляре переменная, оба массива остаются пустыми. Массив напоминаний никогда не копируется с ними.Не удается получить ссылку на массив EKReminder, полученный из fetchRemindersMatchingPredicate
Это метод, который я использую в методе, я создаю предикат, передаю его в хранилище событий, а затем перебираю все напоминания, записывая их заголовок через NSLog. Я вижу заголовки напоминаний во время выполнения благодаря NSLog, но локальный объект arrayOfReminders пуст. Я также пытаюсь добавить каждое напоминание в переменную экземпляра NSMutableArray, но после того, как я покинул блок кода завершения, переменная экземпляра остается пустой.
Я что-то упустил? Может кто-нибудь, пожалуйста, скажите мне, почему я не могу получить ссылку на все напоминания для использования через приложение? У меня нет никаких проблем при доступе и хранении EKEvents, но по какой-то причине я не могу сделать это с помощью EKReminders.
- (void)findAllReminders {
NSPredicate *predicate = [self.eventStore predicateForRemindersInCalendars:nil];
__block NSArray *arrayOfReminders = [[NSArray alloc] init];
[self.eventStore fetchRemindersMatchingPredicate:predicate completion:^(NSArray *reminders) {
arrayOfReminders = [reminders copy]; //Does not work.
for (EKReminder *reminder in reminders) {
[self.remindersForTheDay addObject:reminder];
NSLog(@"%@", reminder.title);
}
}];
//Always = 0;
if ([self.remindersForTheDay count]) {
NSLog(@"Instance Variable has reminders!");
}
//Always = 0;
if ([arrayOfReminders count]) {
NSLog(@"Local Variable has reminders!");
}
}
EventStore getter - это то место, где я выполняю свой экземпляр и получаю доступ к хранилищу событий.
- (EKEventStore *)eventStore {
if (!_eventStore) {
_eventStore = [[EKEventStore alloc] init];
//respondsToSelector indicates iOS 6 support.
if ([_eventStore respondsToSelector:@selector(requestAccessToEntityType:completion:)]) {
//Request access to user calendar
[_eventStore requestAccessToEntityType:EKEntityTypeEvent completion:^(BOOL granted, NSError *error) {
if (granted) {
NSLog(@"iOS 6+ Access to EventStore calendar granted.");
} else {
NSLog(@"Access to EventStore calendar denied.");
}
}];
//Request access to user Reminders
[_eventStore requestAccessToEntityType:EKEntityTypeReminder completion:^(BOOL granted, NSError *error) {
if (granted) {
NSLog(@"iOS 6+ Access to EventStore Reminders granted.");
} else {
NSLog(@"Access to EventStore Reminders denied.");
}
}];
} else { //iOS 5.x and lower support if Selector is not supported
NSLog(@"iOS 5.x < Access to EventStore calendar granted.");
}
for (EKCalendar *cal in self.calendars) {
NSLog(@"Calendar found: %@", cal.title);
}
[_eventStore reset];
}
return _eventStore;
}
Наконец, просто чтобы показать, что я инициализация моего переменного экземпляра remindersForTheDay используя ленивый экземпляр.
- (NSMutableArray *)remindersForTheDay {
if (!_remindersForTheDay) _remindersForTheDay = [[NSMutableArray alloc] init];
return _remindersForTheDay;
}
Я прочитал документацию Apple и не дает никаких объяснений, которые я могу найти, чтобы ответить на это. Я читаю через Blocks Programming docs и заявляет, что вы можете получить доступ к локальным и переменным экземпляра без проблем изнутри блока, но по некоторым причинам приведенный выше код не работает.
Любая помощь будет принята с благодарностью, я подсчитал Google ответы, но еще не понял это.
Спасибо всем!
Johnathon.
UPDATE:
С тех пор я создал новое приложение, которое не делает ничего, кроме, например хранилище событий, настройки вида таблицы, настроить КВО и обновляет пользовательский интерфейс в соответствии с рекомендациями, содержащимися. Код ниже - это приложение полностью. UITableView никогда не обновляется содержимым напоминаний. Приложение запускается и смотрит на меня. В результате вызова метода reloadData в конечном итоге должен быть обновлен пользовательский интерфейс с данными напоминания.
Данные напоминания существуют в self.reminders, потому что мой NSLog выводит, что у меня есть 372 объекта в массиве.
Наконец, если я касаюсь UITableView на устройстве, приложение вылетает с «NSInternalInconsistencyException», причина: «UITableView dataSource должен вернуть ячейку из tableView: cellForRowAtIndexPath:».
@import EventKit;
#import "RTViewController.h"
@interface RTViewController()
@property (weak, nonatomic) IBOutlet UITableView *tableView;
@property (strong, nonatomic) EKEventStore *eventStore;
@property (strong, nonatomic) NSArray *reminders;
@property (nonatomic) BOOL accessGranted;
@property (strong, nonatomic) NSDate *date;
@end
@implementation RTViewController
- (EKEventStore *)eventStore {
if (!_eventStore) {
_eventStore = [[EKEventStore alloc] init];
if ([_eventStore respondsToSelector:@selector(requestAccessToEntityType:completion:)]) {
[_eventStore requestAccessToEntityType:EKEntityTypeReminder completion:^(BOOL granted, NSError *error) {
if (granted) self.accessGranted = YES;
else self.accessGranted = NO;
}];
}
[_eventStore reset];
}
return _eventStore;
}
- (void)viewDidLoad
{
[super viewDidLoad];
self.reminders = [[NSArray alloc] init];
self.date = [NSDate date]; //Returns NSDate allocated/init to NOW
NSPredicate *predicate = [self.eventStore predicateForRemindersInCalendars:nil]; //nil will cause all calendars to be used.
//Ran on different thread.
[self.eventStore fetchRemindersMatchingPredicate:predicate completion:^(NSArray *reminders) {
_reminders = [reminders copy]; //NEVER happens.
[self updateReminders];
}];
//Setup the "radio" and watch ourself for when self.reminders is changed from the other thread
[self addObserver:self forKeyPath:@"reminders" options:(NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld) context:NULL];
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
//If no data exists, then this will return 0 so no rows created.
return [self.reminders count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [self.tableView dequeueReusableCellWithIdentifier:@"cell"];
if (self.reminders) {
EKReminder *reminder = self.reminders[indexPath.row];
cell.detailTextLabel.text = reminder.title;
}
return cell;
}
//Called by self when self.remidners is changed. - NEVER gets called.
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
[self.tableView reloadData];
}
- (void)updateReminders {
NSLog(@"%d objects found in array", [self.reminders count]);
[self.tableView reloadData];
}
@end
Первой проблемой с обновлением является то, что вы обращаетесь непосредственно к '_reminders', вместо использования' self.reminders'. Первый никогда не будет запускать KVO. Вторая проблема может заключаться в том, что вы можете обновлять пользовательский интерфейс (вызывающий 'reloadData') вне основного потока. Я рекомендую использовать что-то вроде 'dispatch_async (dispatch_get_main_queue(),^{[self.tableView reloadData];}'. В-третьих, я не вижу, что вы регистрируете ячейки, поэтому вам нужно проверить, что 'cell'' nil' и создать его с нуля. Любой базовый учебник 'UITableView' должен показать вам, как это сделать. – yonosoytu
Я действительно сделал это в тот же вечер в воскресенье, когда пользовательский интерфейс обновления перешел на основной поток. Начиная с iOS 6, t нужно зарегистрировать ячейки, представление таблицы будет экземпляром нового, для вас одного из них не существует, при условии, что ячейка была создана в построителе интерфейса (моя была). Ввод вызова пользовательского интерфейса обновления в основной поток и настройка KVO исправил проблему для меня. Спасибо за помощь. –
Кроме того, в документации на яблоки сказано, что вы можете обращаться к переменным экземпляра напрямую, а не к их свойствам изнутри блока кода, поэтому причина, по которой я обращался с помощью _reminders. напоминания = напоминания; в отличии t и вызвал его изнутри кодового блока. –