1

これについてどうすればよいですか?

私はUISwitchを持っています。ユーザーがスイッチをタップすると、驚くべきことが起こります!

ここで、ユーザーがスイッチをダブルタップすると、驚くべきクラッシュが発生します! 最初のタップはまだ素晴らしいことをしていたからです!

私がやろうとしているのはこれです、

ユーザータップ:

1 - toggleOvertimeSwitch が呼び出されます

2 -スイッチからターゲットを削除します(ダブルタップが発生した場合に呼び出されないようにするため)

3 -素晴らしいことをする

4 -ターゲットを再度追加

後でスイッチの位置に注意する必要があるいくつかの懸念がありますが、一見すると、これでうまくいくはずです。しかし、そうではありません。

ターゲットから自分自身を削除していますが、それでもすべてのタップに反応し続けます! toggleOvertimeSwith は常に呼び出されています。理由がわかりません。

誰でもこれを理解するのを手伝ってもらえますか?

ありがとうございました!

ヌーノ

コード:

私のviewDidLoadはこれを実装しています、

[self.toggleSwitch addTarget:self
                      action:@selector(toggleOvertimeSwitch:)
            forControlEvents:UIControlEventValueChanged];

そして、私の toggleOvertimeSwitch はこれを実装しています。

-(void)toggleOvertimeSwitch:(UISwitch *)sender
{

[self.toggleSwitch removeTarget:self
                         action:@selector(toggleOvertimeSwitch:)
               forControlEvents:UIControlEventValueChanged];

// Do something amazing here


[self.toggleSwitch addTarget:self
                      action:@selector(toggleOvertimeSwitch:)
            forControlEvents:UIControlEventValueChanged];

}
4

3 に答える 3

1
  • 「何か素晴らしいことをする」という部分がコードの残りの部分と同じスレッド/キューで実行される場合、すべてのイベント/使用アクションはメインスレッドで処理されるため、何も変更されません。toggleOvertimeSwitch:最後まで、メソッド自体が終了する前に、ユーザーの操作によってトリガーされたこのメソッドの中断やその他の呼び出しはありません。

  • 「驚くべきこと」のコードが別のスレッドで実行される場合 (たとえば、GCDdispatch_async関数を使用する場合)、switch アクションを無効にすることは意味がありますが、次のようになります。

    • スイッチアクションを再アクティブ化する前に、「すばらしい作業」が完了するのを待つ必要があります。これは、実際にそこで非同期に何かを実行しているかのように、非同期コードが完了するのを待たずに、ターゲット/アクションを再追加するコードが実行されます。定義により、アクションが完了する前にスイッチが再度有効になります
  • それでも、enabledターゲット/アクションを削除して再度追加するのではなく、スイッチのプロパティを使用して無効にして再度有効にする必要があります。はるかに簡単です!

GCDやスレッドコードなどを実際に使用して「素晴らしい仕事」を行っているかどうかはわかりません.それについての質問にはあまり情報がありませんでした.たとえば、dispatch_async の場合、sthg は次のようになります。

-(IBAction)toggleOvertimeSwitch:(UISwitch*)sender
{
    // disable the switch
    sender.enabled = NO;

    // start your long background work
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_NORMAL, 0), ^{
      // ... some amazing work in the background, executed asynchronously ...

      // Then, when finished, re-enable the switch:
      dispatch_sync(dispatch_get_main_queue(), ^{
        sender.enabled = YES;
      });
    });
}

PS : 繰り返しますが、バックグラウンドで実行されるスレッド化コードも非同期コードも使用せず、現在のスレッドで同期的に実行されるコードを使用する場合、すべてのtoggleOvertimeSwitch:メソッドはでのみ実行されるため、問題はまったく存在しません。中断することなく 1 つのステップを実行し、次の UI イベント (タッチなど) はその後にのみ処理されます。

于 2012-10-01T23:04:28.887 に答える
1

メソッドの開始時に、次のようdoSomethingAmazing:に言います。

mySwitch.userInteractionEnabled = NO;

...そして の最後のものとしてdoSomethingAmazing:

mySwitch.userInteractionEnabled = YES;

これにより、準備が整うまで、ターゲット/アクションセレクターが再び起動されるのを防ぎます。

于 2014-11-21T09:59:07.620 に答える
0

私の推測では、あなたの仮定がここにあるのですぐにはaddTarget起こりremoveTargetませんが、後で発生するスレッドでキューに入れられます。ターゲットを削除して再度追加するのではなく、「驚くべきことを行う」ためのメソッドがスレッドセーフであることを確認することをお勧めします。プロパティをアトミックに変更するか、他の同期メカニズムを使用する必要がある場合があります。

「驚くべき」方法で何をしているのか、そしてクラッシュの正確な内容について詳細を提供していただければ、そこに何かを見つけることができるかもしれません.

于 2012-10-01T22:49:08.043 に答える