3

iPhoneアプリでUIActionSheetを使用している間、アクションをボタンに一致させる一般的な方法は非常に壊れやすく、見た目にも不快に見えます。おそらくそれは私の最小限のC/C ++バックグラウンド(より多くのPerl、Java、Lispなど)によるものです。ボタンインデックスの一致は、単純な論理エラーまたは整合性エラーを回避するには、マジックナンバーが多すぎて接続が切断されているように見えます。

例えば、

UIActionSheet *sources = [[UIActionSheet alloc]
         initWithTitle:@"Social Networks"
              delegate:self 
     cancelButtonTitle:@"Cancel" 
destructiveButtonTitle:nil 
     otherButtonTitles:@"Twitter", @"Facebook", @"Myspace", @"LinkedIn", @"BlahBlah", nil
];

<snip>

-(void)actionSheet:(UIActionSheet *)actionSheet didDismissWithButtonIndex:(NSInteger)buttonIndex {
    if (buttonIndex == [actionSheet cancelButtonIndex]) {
        // all done
    } else if (buttonIndex == 0) {
        // Twitter
    } else if (buttonIndex == 1) {
        // Facebook
    } else if (buttonIndex == 2) {
        // LinkedIn
    } else if (buttonIndex == 3) {
        // Myspace
    }
}

アクション処理コードに少なくとも2つのエラーがあることに注意してください(少なくともコメントによると)。

私が見逃しているのは、Objective-Cでその切断を回避するための正しいデザインパターンです。これがperlの場合、最初にボタンオプションの配列を作成し、次に各アイテムに適切な処理を行うオブジェクトまたはサブルーチンの別のルックアップテーブルに対応するクイックルックアップテーブルハッシュを作成します。Javaでは、元のリストはおそらく最初にコールバックを持つオブジェクトになります。Perlハッシュを模倣する辞書を作成できることは知っていますが、3〜4個のオプションでは非常に扱いにくく面倒です。インデックスの魔法性を隠すために列挙型を使用することも検討しましたが、それは問題のごく一部にすぎません。

本当の問題は、ボタン文字列のリストと対応するアクションの両方を1つの場所で指定する(簡単な?)方法がないため、オプションを追加/削除/並べ替えるときに2つの場所でコードを変更する必要がなくなり、効果的に作成できることです。私のサンプルコードが犯すような間違いを犯すことは不可能です。

私はプログラミング言語の聖戦を始めようとはしていません。ボタン文字列のリストをアクションのリストに接続するためのこのシナリオ(およびObjective Cの他の多くのシナリオ)の正しいデザインパターンを理解したいだけです。

4

5 に答える 5

4

私はこの方法を好みます

- (void)actionSheet:(UIActionSheet *)actionSheet didDismissWithButtonIndex:(NSInteger)buttonIndex {
    if (buttonIndex == [actionSheet cancelButtonIndex]) 
    {
       // cancelled, nothing happen
       return;
    }

    // obtain a human-readable option string
    NSString *option = [actionSheet buttonTitleAtIndex:buttonIndex];
    if ([option isEqualToString:@"Twitter"])
    {
        //...
    } else if ([option isEqualToString:@"FaceBook"])
    {
        //...
    }
}
于 2010-10-20T04:04:37.683 に答える
3

私はその質問に完全に同意します。ここでの Apple の設計では、マジック ナンバーの使用が奨励されており、ボタン インデックスにハードコードされた数字の使用を推奨しているすべてのソリューションを見て、少しショックを受けました。

これがSwiftの私のソリューションです。

  • 次のように、すべてのボタン タイトルのアイテムを含む列挙型を作成します。
enum ImagePickerActionSheetButtons
{
    case Camera
    case Chooser
}

各ボタン タイトルの LOCALIZED 文字列を辞書に入力します。キーは列挙型の項目です。

// Populate with LOCALIZED STRINGS
var buttonTitles:[ImagePickerActionSheetButtons:String] =
[ImagePickerActionSheetButtons.Camera:"Take photo",
    ImagePickerActionSheetButtons.Chooser :"Choose photo"]

列挙値によって辞書からボタンのタイトルを取得して、アクション シートを作成します。

func createActionSheet()->UIActionSheet
{
    var sheet: UIActionSheet = UIActionSheet()

    sheet.addButtonWithTitle(buttonTitles[.Camera]!)
    sheet.addButtonWithTitle(buttonTitles[.Chooser]!)

    sheet.addButtonWithTitle("Cancel")
    sheet.cancelButtonIndex = sheet.numberOfButtons - 1
    sheet.delegate = self
    return sheet
}

最後に、clickedButtonAtIndex コードで、クリックされたボタンのタイトルを辞書内のローカライズされた文字列と照合します。

func actionSheet(sheet: UIActionSheet!, clickedButtonAtIndex buttonIndex: Int)
{
    if (sheet.buttonTitleAtIndex(buttonIndex) == buttonTitles[.Camera]!)
    {
        takePhoto()
    }
    else if (sheet.buttonTitleAtIndex(buttonIndex) == buttonTitles[.Chooser]!)
    {
        choosePicFromLibrary()
    }
    else if (buttonIndex == sheet.cancelButtonIndex)
    {
        // do nothing
    }
}
于 2015-03-26T06:12:12.030 に答える
1

ボタンのアクションを配列に入れることができるかもしれません

actionsArray = [NSMutableArray arrayWithObjects: @selector(btn1Clicked),    
                                    @selector(btn2Clicked), 
                                    @selector(btn3Clicked), 
                                    @selector(btn4Clicked), nil];

その後、didDismissWthButtonIndex

-(void)actionSheet:(UIActionSheet *)actionSheet didDismissWithButtonIndex:(NSInteger)buttonIndex {
    if (buttonIndex == [actionSheet cancelButtonIndex]) {
        // all done
    } else {
       [this [actionsArray objectAtIndex: buttonIndex]];
    }
}

ボタン情報とメソッドを含むより複雑なオブジェクトを配列に入れ、それをすべて配列に含めることができると確信しています。おそらく、配列のインデックスのエラーチェックが改善されます....など

正直に言うと、質問を読むまでこのパターンについてあまり考えたことがなかったので、これは私の頭の中から外れています

于 2010-10-20T03:27:48.020 に答える
1

あれはどうですか?

このように、ボタンとアクションが同じ場所に追加されるため、インデックスを気にする必要はありません。

typedef void (^contact_callback_t)(MyContactsController *controller);
 … 
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
     NSDictionary *contact = [myContacts objectAtIndex:indexPath.row];     
     UIActionSheet *_actionSheet = [[UIActionSheet alloc] initWithTitle:NSLocalizedString(@"Contact Action", @"")
                                                          delegate:self
                                                 cancelButtonTitle:nil
                                            destructiveButtonTitle:nil
                                                 otherButtonTitles:nil];

 _actions = [NSMutableArray new];
 if([contact objectForKey:@"private_email"] != nil) {
     [_actionSheet addButtonWithTitle:
      [NSString stringWithFormat:NSLocalizedString(@"E-Mail: %@", @""), [contact objectForKey:@"private_email"] ] ];
     contact_callback_t callback = ^(MyContactsController *controller) {
         [controller openEmail:contact];
     };
     [_actions addObject:callback];
 }
 if([contact objectForKey:@"private_telefon"] != nil) {
     [_actionSheet addButtonWithTitle: 
      [NSString stringWithFormat:NSLocalizedString(@"Phone: %@", @""), [contact objectForKey:@"private_telefon"] ]];
     contact_callback_t callback = ^(MyContactsController *controller) {
         [controller dial:[contact objectForKey:@"private_telefon"]];
     };
     [_actions addObject:callback];
   }
  [_actionSheet showFromTabBar:tabBar];     

}

- (void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex 
{
  if(buttonIndex == actionSheet.cancelButtonIndex)
{
}
else
{
      contact_callback_t callback = [_actions objectAtIndex:buttonIndex];
      callback(self);
   }
  _actions = nil;
}
于 2012-05-25T00:52:12.077 に答える
-1

Aaron のセレクターの提案に基づいて、単純なアドホック ディスパッチ メソッドを実行するというアイデアが気に入っています。間違ったオプションを処理する可能性をうまく回避し、懸念事項のクリーンな因数分解を提供します。もちろん、Toro の回答のように、オブジェクトをインスタンス化してオプション文字列を渡すなど、オプションごとに最初に何か他のことをしたいユースケースを想像することもできます。

「actionTwitter」などのメソッドを呼び出す簡単なディスパッチを次に示します。

-(void)actionSheet:(UIActionSheet *)actionSheet didDismissWithButtonIndex:(NSInteger)buttonIndex {  
    if (buttonIndex == [actionSheet cancelButtonIndex]) {
        return;
    }

    NSString *methodName = [@"action" stringByAppendingString:[actionSheet buttonTitleAtIndex:buttonIndex]];
    SEL actionMethod = NSSelectorFromString(methodName);
    if ([self respondsToSelector:actionMethod]) {
        [self performSelector:actionMethod];
    } else {
        NSLog(@"Not yet implemented")
    }
}
于 2010-10-20T05:26:18.423 に答える