2010-09-20 30 views
8

Tôi cần thực hiện chặn UIAlertView. Bởi vì tôi có chức năng và tôi cần phải trả lại lựa chọn UIAlertView. Nhưng vấn đề là sau khi UIAlertView được hiển thị mã chức năng của tôi đang thực hiện thêm vì vậy tôi không thể bắt được sự lựa chọn UIAlertView (tôi có thể làm điều đó theo phương pháp đại biểu, nhưng tôi cần trả về kết quả hàm).Chặn UIAlertView

Tôi đã cố gắng thực hiện chặn UIAlertVIew với NSCondition. Nhưng mã không hoạt động.

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

Có thể cách sửa mã này hoặc bất kỳ đề xuất nào khác? Cảm ơn

Trả lời

8

Không có cách nào để đạt được những gì bạn muốn. Chỉ thông qua các đại biểu. Bạn nên thiết kế lại chức năng của mình hoặc từ chối sử dụng UIAlertView

+0

Cảm ơn. Tôi đã thiết kế lại logic chức năng của mình. – kesrut

2

Tôi vừa gặp phải vấn đề tương tự. Mặc dù không có giải pháp, có ít nhất 2 cách giải quyết mà tôi nghĩ đến.

Vòng "giải pháp" Ngay sau khi bạn gọi UIAlert bạn bắt đầu vòng lặp tìm kiếm thay đổi trong biến toàn cục cho đối tượng của bạn (không phải toàn bộ dự án, nhớ bạn) biến đó là biến bạn đặt trong đại biểu UIAlert nhận câu trả lời. Vì vậy, về cơ bản bạn chờ đợi cho "là A == 1, nếu không DoEvents" và vòng lặp trên đó.

Sau đó, trên các đại biểu bạn thực hiện A = 1 khi bạn có câu trả lời

và trước khi ai đó nói rằng không có DoEvents trong Cocoa:

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

Đại biểu Solution Thay vì có mã mà trả lời A, B hoặc C trong hàm gọi Alert, có mã trong chính ủy nhiệm.

Hy vọng điều đó sẽ hữu ích. Tôi đã sử dụng cái thứ hai trong dự án của mình và nó đã hoạt động.

+0

OP là sau một giải pháp cho iOS, mà tôi không nghĩ rằng đây là. –

1

Tôi chỉ tìm thấy câu hỏi này một cách tình cờ và thậm chí bằng cách nhập của Apple địa ngục bằng cách đăng này, tôi xin tuyên bố này như một bằng chứng của khái niệm:

@interface EvilShitClass() <UIAlertViewDelegate> 
@end 

@implementation EvilShitClass { 
    BOOL _isCanceled, _wasYes; 
} 

Dưới đây là phương pháp tĩnh cho một yes/no truy vấn:

+ (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; 
} 

và cuối cùng là phương pháp đại biểu để xử lý các nút bấm và ngăn chặn các runloop chế biến:

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

Tác phẩm này nhưng hãy nhớ: bạn không nên làm theo cách này :-D Rất vui lòng không tranh luận về phong cách và nội dung, nó chỉ là 5 phút nhanh chóng hack để chứng minh nó có thể được thực hiện! Điều này sẽ làm việc mà không có ARC (mới -> autorelease) nhưng nếu tôi sai bạn biết làm thế nào để xử lý nó;)

Tuyên bố từ chối trách nhiệm: Tôi không chịu trách nhiệm cho bất kỳ thiệt hại có thể sử dụng đoạn mã này có thể làm cho bạn ứng dụng hoặc thiết bị. Cảm ơn bạn.

5

Điều này không làm cho nó chặn, nhưng tôi đã viết một lớp con để thêm cú pháp kiểu khối giúp dễ dàng xử lý phương thức buttonClickedAtIndex mà không cần phải làm đại biểu UIAlertViews trong một lớp.

#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 

Sau đó, gọi đây là một số mã ví dụ. Phần thú vị khác là bởi vì một khối đóng xung quanh các biến cục bộ, tôi có thể có quyền truy cập vào tất cả trạng thái đã tồn tại tại thời điểm tôi hiển thị UIAlertView. Sử dụng phương pháp đại biểu truyền thống, bạn sẽ phải lưu trữ tất cả trạng thái tạm thời đó thành các biến cấp lớp để có quyền truy cập vào nó trong lệnh gọi buttonClickedAtIndex trong ủy nhiệm. Điều này là sạch hơn rất nhiều.

{ 
    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

Cảm ơn bạn @Joseph. Điều này hoàn toàn điên rồ toàn bộ cảnh báo và đại biểu điên cuồng. Cảm ơn vì giải pháp này. – Eddy

1

Sử dụng UIAlertView với các khối từ Joseph và thêm một semaphore vào nó. Khai báo một semaphore toàn cầu

dispatch_semaphore_t generateNotificationsSemaphore; 

Và tín hiệu semaphore trong khối xử lý

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

    } else { 

    } 

    dispatch_semaphore_signal(generateNotificationsSemaphore); 
}]; 

Sau khi gọi các showWithHandler thêm một vòng lặp chờ đợi bằng cách sử dụng semaphore

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

} 

trị thời gian chờ thực tế của bạn có thể khác nhau tùy theo nhu cầu của bạn.

Các vấn đề liên quan