2010-09-20 10 views
8

Potrzebuję zablokować UIAlertView. Ponieważ mam funkcję i muszę zwrócić wybór UIAlertView. Ale problem polega na tym, że po wyświetleniu UIAlertView mój kod funkcji jest wykonywany dalej, więc nie mogę złapać wyboru UIAlertView (mogę to zrobić w metodach delegatów, ale muszę zwrócić wynik funkcji).UIAlertView blokowanie

Próbowałem zablokować za pomocą NSCondition. Ale kod nie działa.

condition = [NSCondition new]; 
result = 0 ; 
[condition lock]; 
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Fingerprint" message:@"test" delegate:window_self cancelButtonTitle:@"No" otherButtonTitles:@"Yes",nil]; 
[alert setDelegate:self]; 
[alert show]; 
while (result == 0) [condition wait]; 
[condition unlock] ; 

- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex 
{ 
[condition lock] ; 
if (buttonIndex == 0) 
{ 
    result = 2; 
} 
else if (buttonIndex == 1) 
{ 
    result = 3 ; 
} 
[condition signal] ; 
[condition unlock] ; 
} 

Może naprawić ten kod lub inne sugestie? Dzięki

Odpowiedz

8

Nie ma sposobu, aby osiągnąć to, co chcesz. Tylko za pośrednictwem delegata. Powinieneś przeprojektować swoją funkcję lub odmówić użycia UIAlertView

+0

Dzięki. Przeprojektowałem moją logikę funkcji. – kesrut

2

Po prostu miałem ten sam problem. Chociaż nie ma rozwiązania, istnieją co najmniej dwa obejścia, o których myślałem.

Pętla "rozwiązanie" Zaraz po wywołaniu UIAlert uruchamiasz pętlę, która szuka zmiany w zmiennej, która jest globalna dla twojego obiektu (nie dla całego projektu, pamiętaj), że zmienna jest tą, którą ustawiłeś w delegacie UIAlert, który bierze odpowiedzi. Zasadniczo więc czekasz na "to A == 1, jeśli nie DoEvents" i zapętlaj go.

Następnie na delegata zrobić A = 1, gdy masz odpowiedź

i zanim ktoś mówi, że nie ma DoEvents w kakao:

void MyTestClass::DoEvents() 
{ 

  NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; 
  NSEvent* event = [NSApp nextEventMatchingMask:NSAnyEventMask 
    untilDate:[NSDate distantPast] 
    inMode:NSDefaultRunLoopMode 
    dequeue:YES]; 
  if (event) { 
    [NSApp sendEvent:event]; 
    [NSApp updateWindows]; 
  } 
  [pool release]; 
} 

Delegat Rozwiązanie Zamiast kod zajmuje się odpowiedzią A, B lub C w funkcji, która wywołuje Alert, posiada kod w samym uczestniku.

Mam nadzieję, że to pomaga. Użyłem drugiej w moim projekcie i działało.

+0

OP był po rozwiązaniu dla iOS, co nie wydaje mi się, że tak jest. –

1

Właśnie znalazłem na to pytanie przez przypadek i nawet wprowadzając Jabłko piekło zamieszczając to ja ogłaszam to jako dowód pojęcia:

@interface EvilShitClass() <UIAlertViewDelegate> 
@end 

@implementation EvilShitClass { 
    BOOL _isCanceled, _wasYes; 
} 

Oto statyczna metoda tak/nie zapytań:

+ (BOOL)yesNoQueryWithTitle:(NSString*)title text:(NSString*)text { 

    EvilShitClass *shit = [EvilShitClass new]; 
    UIAlertView *alertView = [UIAlertView new]; 
    alertView.delegate = shit; 
    alertView.title = title; 
    alertView.message = text; 
    [alertView addButtonWithTitle:@"Yes"]; 
    [alertView addButtonWithTitle:@"No"]; 

    NSRunLoop *run_loop = [NSRunLoop currentRunLoop]; 

    [alertView show]; 

    while(!shit->_isCanceled) { 
     BOOL tmp = [run_loop runMode:NSDefaultRunLoopMode beforeDate:[NSDate date]]; 
    } 

    return shit->_wasYes; 
} 

i wreszcie metoda delegat do obsługi przycisku kliknięcie i zatrzymać runloop-technologicznego:

- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex { 
    _wasYes = (buttonIndex == 0); 
    _isCanceled = YES; 
} 

To działa, ale pamiętaj: nie powinieneś robić tego w następujący sposób :-D Dość proszę, nie kłóćcie się o styl i tak dalej, to tylko 5-minutowy szybki hack na dowód, że można to zrobić! To powinno działać bez ARC (nowe -> autorelease) , ale jeśli się mylę, wiesz, jak sobie z tym poradzić;)

Oświadczenie: nie ponoszę odpowiedzialności za jakiekolwiek szkody, które może spowodować wykorzystanie tego fragmentu aplikacja lub urządzenia. Dziękuję Ci.

5

To nie blokuje, ale napisałem podklasę, aby dodać składnię stylu blokowego, co znacznie ułatwia obsługę metody buttonClickedAtIndex bez konieczności wykonywania delegata i całej grupy instrukcji if, jeśli masz wiele UIAlertViews w jednej klasie.

#import <UIKit/UIKit.h> 

@interface UIAlertViewBlock : UIAlertView<UIAlertViewDelegate> 
- (id) initWithTitle:(NSString *)title message:(NSString *)message block: (void (^)(NSInteger buttonIndex))block 
    cancelButtonTitle:(NSString *)cancelButtonTitle otherButtonTitles:(NSString *)otherButtonTitles, ... NS_AVAILABLE(10_6, 4_0); 
@end 


#import "UIAlertViewBlock.h" 

@interface UIAlertViewBlock() 
{ 
    void (^_block)(NSInteger); 
} 
@end 

@implementation UIAlertViewBlock 

- (id) initWithTitle:(NSString *)title message:(NSString *)message block: (void (^)(NSInteger buttonIndex))block 
cancelButtonTitle:(NSString *)cancelButtonTitle otherButtonTitles:(NSString *)otherButtonTitles, ... NS_AVAILABLE(10_6, 4_0) 
{ 
    if (self = [super initWithTitle:title message:message delegate:self cancelButtonTitle:cancelButtonTitle otherButtonTitles:otherButtonTitles, nil]) 
    { 
     _block = block; 
    } 
    return self; 
} 

- (void) alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex 
{ 
    _block(buttonIndex); 
} 

@end 

Następnie, aby wywołać to tutaj, jest przykładowy kod. Drugą fajną częścią jest to, że ponieważ blok zamyka się wokół zmiennych lokalnych, mogę mieć dostęp do całego stanu istniejącego w czasie, gdy wyświetlam UIAlertView. Korzystając z tradycyjnego podejścia delegującego, należałoby zapisać cały ten tymczasowy stan w zmiennych klasowych, aby uzyskać do niego dostęp w wywołaniu przyciskuClickedAtIndex w delegacie. To jest o wiele czystsze.

{ 
    NSString *value = @"some random value"; 
    UIAlertViewBlock *b = [[UIAlertViewBlock alloc] initWithTitle:@"Title" message:@"Message" block:^(NSInteger buttonIndex) 
     { 
      if (buttonIndex == 0) 
       NSLog(@"%@", [value stringByAppendingString: @" Cancel pressed"]); 
      else if (buttonIndex == 1) 
       NSLog(@"Other pressed"); 
      else 
       NSLog(@"Something else pressed"); 
     } 
     cancelButtonTitle:@"Cancel" otherButtonTitles:@"Other", nil]; 

    [b show]; 
} 
+1

Dziękuję @ Joseph. To jest kompletnie szalone w całym widoku alertu i deleguje szaleństwo. Dzięki za to rozwiązanie. – Eddy

1

Użyj UIAlertView z blokami z Joseph i dodaj semafor do niego. stwierdzenie globalny semafor

dispatch_semaphore_t generateNotificationsSemaphore; 

i sygnał semafora w obsługi bloku

[alert showWithHandler:^(UIAlertView *alertView, NSInteger buttonIndex) { 
    if (buttonIndex == [alertView cancelButtonIndex]) { 

    } else { 

    } 

    dispatch_semaphore_signal(generateNotificationsSemaphore); 
}]; 

Po wywołaniu showWithHandler dodać pętlę oczekiwania za pomocą semafora

while (dispatch_semaphore_wait(generateNotificationsSemaphore, DISPATCH_TIME_NOW)) { 
    [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate dateWithTimeIntervalSinceNow:20]]; 

} 

rzeczywistą wartość limitu czasu może różnić się w zależności od Twoich potrzeb.