0

私はステータス アプリケーションを持っています。すべてを投稿するには長いので、それについて説明し、コードの一部のみを投稿します。

  • xib ファイルには、AboutController と PreferencesController の 2 つのオブジェクトがあります。
  • アプリ デリゲートは、AboutController と PreferencesController のパネルを起動できます。
  • パネルも xib ファイルに含まれています。
  • ユーザーは、ステータス メニュー項目を選択して、これら 2 つのパネルを起動できます。
  • 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];

timer はプロパティです:

@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 に答える