0

我有一个消息应用程序,我开始创建一个小部件。当用户打开应用程序时,会使用新消息更新核心数据。我的愿望是:

- (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 步中的值为零。我能做些什么?

4

1 回答 1

1

出现nil问题是因为您尝试从小部件访问应用程序的情节提要。这并不简单,因为包含的应用程序和小部件扩展被保存在单独的包中。因此[NSBundle mainBundle],步骤 2) 中的捆绑包与您的应用程序中的捆绑包不同。

可能的解决方案包括:

  • 通过将应用程序添加到小部件目标选项卡的列表中或仅将小部件目标添加到目标成员列表中,将应用程序包含Main.storyboard在扩展包中Copy Bundle resourcesBuild PhasesMain.storyboard

  • 将负责获取消息的代码移动MainController startGetMessages: 到一个共享框架中,该框架可以从应用程序和小部件访问,最好是移动到一个专用对象中。

第二个更好。根据经验,在进行面向对象编程时最好遵循SOLID原则,其中S代表单一职责视图控制器不应该负责提供系统范围的消息获取。创建一个只有一项工作的专用对象 - 获取消息 - 并在目标之间共享它是一种方法。

有关如何创建共享框架的详细说明,请参阅文档:https ://developer.apple.com/library/prerelease/ios/documentation/General/Conceptual/ExtensibilityPG/ExtensionScenarios.html#//apple_ref/doc/ uid/TP40014214-CH21-SW1

于 2014-12-25T16:55:03.200 回答