0

我有一个状态应用程序,发布它很长,所以我将对其进行描述并仅发布部分代码:

  • 在 xib 文件中有两个对象:AboutController 和 PreferencesController;
  • 应用程序委托能够启动 AboutController 和 PreferencesController 的面板;
  • 面板也在 xib 文件中;
  • 用户通过选择状态菜单项可以启动这两个面板;
  • 有一个计时器可以不断下载 HTML 页面并读取它;
  • 下载页面时,标签的stringValue会发生变化。但stringValue也可能会从PreferencesController中更改。页面是从后台线程下载的,但它是通过主队列更改的。

现在我有一些问题:

  • 当应用程序开始睡眠(计算机进入待机状态)时,我是否必须使计时器无效,并在它返回时创建另一个计时器?
  • 标签在主队列中更新,所以我仍然需要使用互斥锁来保护标签访问?
  • 有时面板丢失:在应用程序启动时,我可以通过单击菜单项来启动面板,但有时它们没有启动。我不知道如何总是重现这个错误,它只是在应用程序时随机发生通常活动 2/3 小时,我必须重新启动应用程序才能解决这个问题。

代码太长,那只是一段代码:

- (void) checkPosts: (id ) sender
{
    NSOperationQueue* queue=[NSOperationQueue new];
    queue.maxConcurrentOperationCount=1;
    [queue addOperationWithBlock:^
    {
        NSNumber* newPosts= [self updatePosts];
        NSNumber* posts= [controller posts];
        if([posts integerValue]!=[newPosts integerValue])
        {
            NSOperationQueue* queue=[NSOperationQueue mainQueue];
            posts= newPosts;
            [queue addOperationWithBlock:^
            {
                // This is where I may have a race condition
                item.attributedTitle=[[NSAttributedString alloc]initWithString: [formatter stringFromNumber: posts] attributes: @{NSForegroundColorAttributeName : [controller color], NSFontAttributeName : [NSFont userFontOfSize: 12.5]}];
            }];
            // That's not so relevant:
            NSUserNotification* notification=[NSUserNotification new];
            notification.title= [NSString stringWithFormat: @"posts Changed to %@",posts];
            notification.deliveryDate=[NSDate date];
            notification.soundName= NSUserNotificationDefaultSoundName;
            NSUserNotificationCenter* center=[NSUserNotificationCenter defaultUserNotificationCenter];
            [center deliverNotification: notification];
            center.delegate= self;
            [controller setPosts: posts];
        }
    }];
}

一点背景资料:

  • 此方法在后台线程中工作;
  • [self updatePosts] 下载 HTML 页面并返回帖子数量;
  • [控制器帖子] 使用 NSUserDefaults 读取之前的帖子数量;
  • item 是状态菜单的菜单项。

更多细节

这就是我获取计时器的方式:

// In the applicationDidFinishLaunching method
timer=[NSTimer scheduledTimerWithTimeInterval: [interval integerValue ] target: self selector: @selector(checkReputation:) userInfo: nil repeats: YES];

计时器是一个属性:

@property (nonatomic, strong) NSTimer* timer;

interval 是一个 NSNumber,确保它的整数值大于或等于 1。

4

1 回答 1

1

目前尚不完全清楚这里发生了什么。您提供了大量信息,但并非提供明确答案所需的所有信息。我将首先尝试解决您的问题:

当应用程序开始睡眠(计算机进入待机状态)时,我是否必须使计时器无效,并在它返回时创建另一个计时器?

不得不?不。应该是为了清洁和确定的状态?很可能是。您可能应该准确指定如何设置计时器,因为您可能会遇到与运行循环交互的问题......但我认为这不是您的问题。

标签在主队列中更新,所以我仍然需要使用互斥锁来保护标签访问?

只要您从主线程/队列更新 UI,就应该没问题。这是带有块的标准设计方法。

有时面板丢失:在应用程序启动时,我可以通过单击菜单项来启动面板,但有时它们没有启动。我不知道如何总是重现这个错误,它只是在应用程序时随机发生通常活动 2/3 小时,我必须重新启动应用程序才能解决这个问题。

如果您不知道如何重现它,我不确定我们能否在“看点”之外为您提供帮助。我的第一个想法是,当应用程序处于活动状态时,您可能正在重新创建主控制器的多个副本(因为您之前询问过这个问题,我假设您已经尝试过使用它做一些事情)。确保重复使用相同的控制器。

现在开始代码。

NSOperationQueue* queue=[NSOperationQueue new];

queue变量是方法范围的局部变量。我看不到保留/释放,所以我假设您使用的是 ARC。在这种情况下,您不会保留您正在创建的新队列,并且只要方法完成并且您离开它的范围,只要您需要它,它的生命周期就不能保证继续存在。您应该创建queue一个实例变量,使其保持不变。这样,每次触发该方法时都可以重用队列,并且它将保持足够长的时间以供其他队列/线程使用。

我认为这可能你最大的罪魁祸首。调整它并更新您的问题,以反映它如何影响您的应用程序的状况。

于 2012-12-22T15:37:28.683 回答