2009-06-30 16 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作爲鍵和上下文作爲值存儲上下文。

然後,當調用alert方法時,只需查看字典以查看哪個上下文對象是相關的。如果你不想使用整個警報對象作爲一個鍵,就可以使用UIAlertView中對象的只是地址:

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

地址應該是在手機上不變。或者,您可以將每個警報標記爲另一個海報的建議,並使用標記在地圖中查找上下文。

當您完成時,不要忘記清除上下文對象!

+0

「地址應該在手機上保持不變」< - 這個地址是指向一個對象的指針,因此不能依賴它來保持常量。其餘的答案是明智的,我只是想指出這一點以備將來參考,以防其他人登陸此頁面。 – Morpheu5 2014-05-19 20:53:41

0

您可以子類UIAlertView並在那裏添加屬性。

7

你也可以使用標籤屬性(因爲它是一個UIView子類)。這只是一個整數,但對你來說可能已經足夠了。

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 2011-06-09 17:02:08

+0

正如@Jeffery托馬斯提到的,UIAlertView的子類化不是一個好主意。 – 2013-03-04 19:26:37

1

我在Kendall的答案和我的一個基本視圖控制器類中的塊的使用之間做了一個混合。現在,我可以使用AlertView和ActionSheets以提高可讀性。以下是我如何做到的:

在。我的ViewController h的我宣佈塊類型(可選,但建議報告)

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

而且我宣佈一個可變dictionnary將存儲塊的每個alertview:

NSMutableDictionary* m_AlertViewContext; 

在實現文件中我添加方法來創建AlertView並保存塊:

-(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精靈)。此外,我還收到一個AlertViewBlock對象,該對象保存在m_AlertViewContext可變詞典中。然後我會像通常那樣顯示警報。

在委託回調,我調用該塊,並給它的參數:

#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]; 
} 

現在,每當我需要使用AlertView我可以這樣調用:

[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"]]; 

我對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,這是一個快速而乾淨的解決方案,利用關聯的對象。我在其他的答案提到,你甚至可以用NSObject取代UIAlertView和有效一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; 

重要提示: 不要忘記在dealloc的背景!