2009-06-30 12 views
15

私のアプリケーションでは、UIAlertViewを使用してメッセージといくつかのオプションをユーザに表示します。押されたボタンに応じて、アプリケーションがオブジェクトに対して何かを実行するようにします。 私が使用したサンプルコード...UIAlertViewデリゲートでコンテキストオブジェクトを安全に渡す方法は?

-(void) showAlert: (id) ctx { 
    UIAlertView *baseAlert = [[UIAlertView alloc] 
          initWithTitle: title 
          message: msg 
          delegate:self 
          cancelButtonTitle: cancelButtonTitle 
          otherButtonTitles: buttonTitle1, buttonTitle2, nil]; 
    //baseAlert.context = ctx; 
    [baseAlert show]; 
    [baseAlert release]; 
} 


- (void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex { 
    if (buttonIndex == 1) { 
     id context = ...;//alertView.context; 
     [self performSelectorOnMainThread:@selector(xxx:) withObject: context waitUntilDone: NO]; 
    } 
} 

コンテキストオブジェクトとしてデリゲートにオブジェクトを渡す方法はありますか?それとも別の方法ですか?

デリゲートにプロパティを追加できましたが、同じデリゲートオブジェクトがさまざまなアラートビューで使用されています。この理由から私は、コンテキストオブジェクトがUIAlertViewインスタンスにアタッチされ、UIAlertViewオブジェクトの一部としてデリゲートに渡されるソリューションを好むでしょう。

答えて

12

私はまだそれをローカルに格納することが最良の解決策だと思います。コンテキストオブジェクトのマップを保持するクラスローカルNSMutableDictionary変数を作成し、キーとしてUIAlertViewを使用してコンテキストを格納し、値としてコンテキストを格納します。

次に、警告メソッドが呼び出されると、辞書に入ってどのコンテキストオブジェクトが関連しているかを調べるだけです。

NSString *alertKey = [NSString stringWithFormat:@"%x", baseAlert]; 

アドレスが携帯電話上で一定でなければならない:あなたがキーとして全体アラートオブジェクトを使用したくない場合は、UIAlertViewオブジェクトのちょうどアドレスを使用することができます。あるいは、他のポスターが示唆しているように各アラートにタグを付けることができ、タグを使用して地図内のコンテキストをルックアップすることもできます。

完了したらコンテキストオブジェクトをクリアすることを忘れないでください!

+0

"アドレスは電話で一定でなければなりません" - このようなアドレスはオブジェクトへのポインタであり、一定のままでは使用できません。あなたの答えの残りは分かりやすいです、私はちょうど誰かがこのページに上陸した場合に備えて、これを将来の参考のために指摘したかったのです。 – Morpheu5

0

UIAlertViewをサブクラス化してプロパティを追加することができます。

7

(これはUIViewサブクラスなので)タグプロパティを使用することもできます。これはちょうどintですが、あなたにとっては十分かもしれません。

10

あなたが文脈通過することを可能にする完全な実装:私たちは、ポインタをキャスト事前どのように注意し、

@interface TDAlertView : UIAlertView 
@property (nonatomic, strong) id context; 
@end 

@implementation TDAlertView 
@end 

と使用例を:

@implementation SomeAlertViewDelegate 
- (void)alertView:(TDAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex { 
    NSLog(@"%@", [alertView context]); 
} 
@end 
+4

私はなぜこのようなものが組み込まれていないのだろうと思っています。デリゲートにコンテキストを渡すのはかなり一般的な問題です。 – pepsi

+0

@Jeffery Thomasが述べたように、UIAlertViewのサブクラス化は良い考えではありません。 –

+1

@ JoshBrown私のサブクラスは、ドキュメントに関する警告であるクラスについては何も修正していません。事実、サブクラスは文法的な砂糖です。 – mxcl

3

サブクラスUIAlertViewは良いアイデアではありません。

http://developer.apple.com/library/ios/#DOCUMENTATION/UIKit/Reference/UIAlertView_Class/UIAlertView/UIAlertView.html

サブクラスノート

UIAlertViewクラスはそのままであり、サブクラス化をサポートしていない使用されることが意図されます。このクラスのビュー階層はプライベートであり、変更することはできません。

UIAlertView with a user supplied context and [self autorelease]はこの質問に別の方法で回答します。

+0

ドキュメントに記載されているように、何も上書きしない限り、サブクラス化することは問題ありません。 – mxcl

+0

@MaxHowellドキュメントの行は「サブクラス化をサポートしていません」です。明示的に禁止するものを暗黙のうちに許可することはできません。ビュー階層の変更は、サブクラス化の禁止に加えて禁止されています。 –

+0

私は、解釈は解釈だと思います。どのようにobjcがどのように動作するのかに関する私の経験と知識、そしてAppleがどのようにクラスを記述しているかに基づいて、私は私の答えでUIAlertViewをサブクラス化することができます。 – mxcl

1

私は、Kendallの答えとベースビューコントローラクラスの1つのブロックの使い方をミックスしました。今では、読みやすさを大幅に向上させるブロックを持つAlertViewとActionSheetsを使用できます。ここで私はそれをやった方法です:

。私のViewControllerの時間、私は(任意ですがrecommanded)ブロックタイプを宣言

typedef void (^AlertViewBlock)(UIAlertView*,NSInteger); 

また、私は、各alertviewのためのブロックを格納する可変dictionnaryを宣言:実装ファイルで

NSMutableDictionary* m_AlertViewContext; 

私が追加します

-(void)displayAlertViewWithTitle:(NSString *)title message:(NSString *)message cancelButtonTitle:(NSString *)cancelButtonTitle withBlock:(AlertViewBlock)execBlock otherButtonTitles:(NSArray *)otherButtonTitles 
    { 
     UIAlertView* alert = [[UIAlertView alloc] initWithTitle:title 
                 message:message 
                 delegate:self cancelButtonTitle:cancelButtonTitle otherButtonTitles: nil]; 
     for (NSString* otherButtonTitle in otherButtonTitles) { 
      [alert addButtonWithTitle:otherButtonTitle]; 
     } 
     AlertViewBlock blockCopy = Block_copy(execBlock); 
     [m_AlertViewContext setObject:blockCopy forKey:[NSString stringWithFormat:@"%p",alert]]; 
     Block_release(blockCopy); 
     [alert show]; 
     [alert release]; 
    } 

注私はUIAlertViewのコンストラクタはなくなりますデリゲート(sと同じ属性を受信します。方法は、ブロックをAlertViewを作成し、保存しますエルフ)。また、私は、m_AlertViewContext可変ディクショナリに保存するAlertViewBlockオブジェクトを受け取ります。 それから私は通常と同じように警告を表示します。

[self displayAlertViewWithTitle:@"Title" 
           message:@"msg" 
         cancelButtonTitle:@"Cancel" 
     withBlock:^(UIAlertView *alertView, NSInteger buttonIndex) { 
      if ([[alertView buttonTitleAtIndex:buttonIndex] isEqualToString:@"DO ACTION"]){ 
       [self doWhatYouHaveToDo]; 
      } 
     } otherButtonTitles:[NSArray arrayWithObject:@"DO ACTION"]]; 

I:私はAlertViewを使用する必要がある時はいつでも、私はこのようにそれを呼び出すことができ、今

#pragma mark - 
#pragma mark UIAlertViewDelegate 

- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex 
{ 
    NSString* blockKey = [NSString stringWithFormat:@"%p",alertView]; 
    AlertViewBlock block = [m_AlertViewContext objectForKey:blockKey]; 
    block(alertView,buttonIndex); 
    [m_AlertViewContext removeObjectForKey:blockKey]; 
} 

- (void)alertViewCancel:(UIAlertView *)alertView { 
    NSString* blockKey = [NSString stringWithFormat:@"%p",alertView]; 
    [m_AlertViewContext removeObjectForKey:blockKey]; 
} 

:デリゲートのコールバックで

、私はパラメータをブロックを呼び出し、それを与えますActionSheetのために同じことをしました、そして、今それらを使用することは本当に簡単です。 お手伝いをしてください。

3

「サブクラス化をサポートしていません」という意味を議論する代わりに、より良い回答を提供します。私は数ヶ月前に私の仕事のための一般的なcontextInfoカテゴリを作成しました。私はちょうどgithubに入れた:JLTContextInfo

#import "objc/runtime.h" 

@interface NSObject (JLTContextInfo) 
- (NSMutableDictionary *)JLT_contextInfo; 
@end 
@implementation NSObject (JLTContextInfo) 
- (NSMutableDictionary *)JLT_contextInfo 
{ 
    static char key; 
    NSMutableDictionary *contextInfo = objc_getAssociatedObject(self, &key); 
    if (!contextInfo) { 
     contextInfo = [NSMutableDictionary dictionary]; 
     objc_setAssociatedObject(self, &key, contextInfo, OBJC_ASSOCIATION_RETAIN_NONATOMIC); 
    } 
    return contextInfo; 
} 
@end 

これにより、NSObjectから派生したオブジェクトの余分なデータを簡単に保存できる場所が作成されます。今の答えは、元の質問とほぼ同じです。

-(void) showAlert: (id) ctx { 
    UIAlertView *baseAlert = [[UIAlertView alloc] 
          initWithTitle: title 
          message: msg 
          delegate:self 
          cancelButtonTitle: cancelButtonTitle 
          otherButtonTitles: buttonTitle1, buttonTitle2, nil]; 
    [[baseAlert JLT_contextInfo] setObject:ctx forKey:@"ctx"]; 
    [baseAlert show]; 
    [baseAlert release]; 
} 

- (void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex { 
    if (buttonIndex == 1) { 
     id context = [[alertView JLT_contextInfo] objectForKey:@"ctx"]; 
     [self performSelectorOnMainThread:@selector(xxx:) withObject: context waitUntilDone: NO]; 
    } 
} 
1

From my other answerは、ここに関連するオブジェクトを活用して、迅速かつクリーンなソリューションです。私は、あなたもNSObjectUIAlertViewを交換し、効果的に任意のオブジェクトにcontextプロパティを追加することができます私の他の答えに言及:

#import <objc/runtime.h> 

@interface UIAlertView (Private) 
@property (nonatomic, strong) id context; 
@end 

@implementation UIAlertView (Private) 
@dynamic context; 
-(void)setContext:(id)context { 
    objc_setAssociatedObject(self, @selector(context), context, OBJC_ASSOCIATION_RETAIN_NONATOMIC); 
} 
-(id)context { 
    return objc_getAssociatedObject(self, @selector(context)); 
} 
@end 

そして、あなたのような何かを行うことができます:

NSObject *myObject = [NSObject new]; 

UIAlertView *alertView = ... 
alertView.context = myObject; 

重要: また、コンテキストをNullにすることを忘れないでください。dealloc !!

関連する問題