Виджет iOS 8, обмен данными между группами приложений вперед и назад

У меня есть приложение для сообщений, и я начал создавать виджет. Обновление основных данных новыми сообщениями происходит, когда пользователь открывает приложение. Мое желание, когда:

- (void)widgetPerformUpdateWithCompletionHandler:(void (^)(NCUpdateResult))completionHandler

вызвал, я получу UIViewController и вызову поток сообщений. Связывание UIViewController с целью моего виджета дало мне ошибку:

'sharedApplication' is unavailable....

Поэтому я отменил это.

Чего я пытаюсь достичь: 1. вызывается widgetPerformUpdateWithCompletionHandler 2. Приложение запускает поток/метод получения сообщений 3. когда оно заканчивается, оно отправляет данные обратно в виджет, используя NSUserDefaults

Мой код:

1:

- (void)widgetPerformUpdateWithCompletionHandler:(void (^)(NCUpdateResult))completionHandler
{
    // Perform any setup necessary in order to update the view.

    [self startGetMessages];

    // If an error is encountered, use NCUpdateResultFailed
    // If there's no update required, use NCUpdateResultNoData
    // If there's an update, use NCUpdateResultNewData

    completionHandler(NCUpdateResultNewData);
}

2:

- (void)startGetMessages
{
    NSLog(@"%s", __PRETTY_FUNCTION__);

    NSBundle *deviceBundle = [NSBundle mainBundle];
    UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"Main" bundle:deviceBundle];
    id MainController = [storyboard instantiateViewControllerWithIdentifier:@"MainTableViewController"];
    SEL getMessagesSelector = NSSelectorFromString(@"startGetMessages:");

    if (MainController)
    {
        NSThread *startGetMessagesThread = [[NSThread alloc] initWithTarget:MainController
                                                                   selector:getMessagesSelector
                                                                     object:StringForInt(HRTableDataSourceKindUpdate)];
        [startGetMessagesThread start];
    }
}

3:

- (void)notifyWidgetForChanges
{

    __block NSMutableDictionary *newMessages = [NSMutableDictionary new];

    NSArray *results = [CoreDataPhotoRecord MR_findAllSortedBy:@"message.originalDate"
                                                     ascending:NO
                                                 withPredicate:[NSPredicate predicateWithFormat:@"(message.delete_message == %@) AND (message.type.integerValue == %d) AND (message.originalDate >= %@)",
                                                                @NO, NORMAL_MESSAGE, _notiftWidgetDate]];

    NSLog(@"%s, _notiftWidgetDate: %@, newMessages.count: %d", __PRETTY_FUNCTION__, _notiftWidgetDate, newMessages.count);

    [results enumerateObjectsUsingBlock:^(CoreDataPhotoRecord *photoDetails, NSUInteger idx, BOOL *stop)
    {
        if (photoDetails != nil && photoDetails.message != nil)
        {
            NSString *cleanMobile = [[ABAddressBook sharedAddressBook] getCleanMobile:photoDetails.message.mobile];
            Contact *person = [[ABAddressBook sharedAddressBook] findContactWithPhoneNumber:cleanMobile];
            ContactWidget *contact = [[ContactWidget alloc] init];
            contact.name = (person != nil && person.name != nil && person.name.length > 0) ? person.name : cleanMobile;

            [newMessages setObject:contact forKey:cleanMobile];
        }
    }];

    [SharedUtilities archiveObject:newMessages.copy forKey:MESSAGES_KEY_NEW widget:true];

    [DEFAULTS_WIDGET setObject:@"111" forKey:@"111"];
    [DEFAULTS_WIDGET synchronize];

    newMessages = nil;
    results = nil;
}

widgetDefaults = [[NSUserDefaults alloc] initWithSuiteName:WIDGET_GROUP_NAME];

Ничего не происходит, так как MainController на шаге 2 равно нулю. Что я могу сделать?


person Idan Moshe    schedule 25.12.2014    source источник


Ответы (1)


Проблема nil возникает из-за того, что вы пытаетесь получить доступ к раскадровке приложения из виджета. Это непросто, так как содержащее приложение и расширение виджета хранятся в отдельных пакетах. Таким образом, [NSBundle mainBundle] на шаге 2) не совпадает с пакетом в вашем приложении.

Возможные решения включают в себя:

  • включая Main.storyboard в пакет расширений приложения, либо добавив его в список Copy Bundle resources на вкладке Build Phases цели виджета, либо просто добавив цель виджета в список Main.storyboard Target Membership.

  • перенос кода, отвечающего за получение сообщений от MainController startGetMessages:, в общую структуру, которая будет доступна как из приложения, так и из виджета, предпочтительно в выделенный объект.

Второй в разы лучше. Как правило, при выполнении объектно-ориентированного программирования лучше всего следовать принципам SOLID, где S означает единая ответственность< /сильный>. контроллер представления не должен нести ответственность за обеспечение выборки сообщений в масштабе всей системы. Создание выделенного объекта, у которого будет только одна задача — получать сообщения, и совместное использование его между целями — это путь.

Подробное объяснение того, как создать общую платформу, см. в документации: https://developer.apple.com/library/prerelease/ios/documentation/General/Conceptual/ExtensibilityPG/ExtensionScenarios.html#//apple_ref/doc/uid/TP40014214-CH21-SW1

person siejkowski    schedule 25.12.2014