2011-05-24 41 views
0

我正在使用郵件核心引擎發送郵件的應用程序。我創建了自己的viewController來發送郵件。我想在郵件發送過程中顯示等待視圖。郵件發送完成後,我的等待視圖始終顯示。這是一種線程問題嗎?使用smtp連接發送郵件時顯示等待視圖?

這是我用來發送郵件的代碼。

- (IBAction) sendTapped:(id) sender { 

[txtfSubject resignFirstResponder]; 
[txtfReceptient resignFirstResponder]; 
[txtvMessageBody resignFirstResponder]; 

[self setTo:txtfReceptient.text]; 
[self setFrom:username]; 
[self setSubject:txtfSubject.text]; 
[self setBody:txtvMessageBody.text]; 

[self performSelector:@selector(prepareAndSendMail) withObject:nil afterDelay:0.34]; 
} 


- (void) prepareAndSendMail { 


[WNAppDelegate performSelectorOnMainThread:@selector(showWaitingView) withObject:nil waitUntilDone:NO]; 

//TODO: send mail here 
CTCoreMessage *msg = [[CTCoreMessage alloc] init]; 
[msg setTo:[myMessage to]]; 
[msg setFrom:[myMessage from]]; 

//Encode message here 
NSString *encodedMessage = nil; 

@try { 
    encodedMessage = [self encodeMessage:txtvMessageBody.text]; 
} 
@catch (NSException * e) { 
    NSLog(@"An exception occurred while encoding message"); 
} 
@finally { 
    if(encodedMessage){ 
     [msg setBody:encodedMessage]; 
    } 
} 

[msg setSubject:[myMessage subject]]; 

BOOL success = [self sendMailOnAnotherThread:msg]; 

[msg release]; 

[WNAppDelegate performSelectorOnMainThread:@selector(removeWaitingView) withObject:nil waitUntilDone:NO]; 
//[appDelegate removeWaitingView]; 
if(!success) { 
    UIAlertView * empty_alert = [[UIAlertView alloc] initWithTitle:@"Error" 
                  message:@"Could not send." 
                  delegate:nil 
               cancelButtonTitle:@"OK" 
               otherButtonTitles:nil]; 
    [empty_alert show]; 
    [empty_alert autorelease]; 
    return; 
} 
else { 
    //Message sent successfully 
    if(self.target && [self.target respondsToSelector:@selector(messageSentSuccessfully)]){ 
     [self.target messageSentSuccessfully]; 
    } 

    WN_POST_NOTIFICATION(kMessageSentSuccessfully,nil); 
} 

[self dismissModalViewControllerAnimated:YES]; 
} 

- (BOOL) sendMailOnAnotherThread:(CTCoreMessage*)message { 


BOOL success = YES; 

BOOL auth = YES; 
BOOL tls = YES; 

@try { 
    [CTSMTPConnection sendMessage:message server:GMAIL_SERVER username:username 
         password:password port:GMAIL_PORT_Number useTLS:tls useAuth:auth]; 
} 
@catch (NSException * e) { 
    //Msg failed to send; 
    success = FALSE; 
} 
return success;  
} 

回答

1

好吧,謝謝你提供的所有信息。問題現在已經解決了。

我在這裏張貼我的代碼,以防萬一有人需要它。

- (IBAction) sendTapped:(id) sender { 

[txtfSubject resignFirstResponder]; 
[txtfReceptient resignFirstResponder]; 
[txtvMessageBody resignFirstResponder]; 

[self setTo:txtfReceptient.text]; 
[self setFrom:username]; 
[self setSubject:txtfSubject.text]; 
[self setBody:txtvMessageBody.text]; 

[self performSelector:@selector(prepareAndSendMail) withObject:nil afterDelay:0.34]; 
} 


- (void) prepareAndSendMail { 

//[((WalnutAppDelegate*)WNAppDelegate) performSelectorOnMainThread:@selector(showWaitingView) withObject:nil waitUntilDone:NO]; 
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; 
NSThread *aNewThread = [[[NSThread alloc] initWithTarget:((WalnutAppDelegate*)WNAppDelegate) selector:@selector(showWaitingView) object:nil] autorelease]; 
[aNewThread start]; 


//[NSThread detachNewThreadSelector: toTarget:((WalnutAppDelegate*)WNAppDelegate) withObject:nil]; 

//TODO: send mail here 
CTCoreMessage *msg = [[CTCoreMessage alloc] init]; 
[msg setTo:[myMessage to]]; 
[msg setFrom:[myMessage from]]; 

//Encode message here 
NSString *encodedMessage = nil; 

@try { 
    encodedMessage = [self encodeMessage:txtvMessageBody.text]; 
} 
@catch (NSException * e) { 
    NSLog(@"An exception occurred while encoding message"); 
} 
@finally { 
    if(encodedMessage){ 
     [msg setBody:encodedMessage]; 
    } 
} 

[msg setSubject:[myMessage subject]]; 

BOOL success = [self sendMailOnAnotherThread:msg]; 

[msg release]; 

//[NSThread detachNewThreadSelector:@selector(removeWaitingView) toTarget:((WalnutAppDelegate*)WNAppDelegate) withObject:nil]; 

[((WalnutAppDelegate*)WNAppDelegate) performSelectorOnMainThread:@selector(removeWaitingView) withObject:nil waitUntilDone:NO]; 
[pool drain]; 


if(!success) { 
    UIAlertView * empty_alert = [[UIAlertView alloc] initWithTitle:@"Error" 
                  message:@"Could not send." 
                  delegate:nil 
               cancelButtonTitle:@"OK" 
               otherButtonTitles:nil]; 
    [empty_alert show]; 
    [empty_alert autorelease]; 
    return; 
} 
else { 
    //Message sent successfully 
    if(self.target && [self.target respondsToSelector:@selector(messageSentSuccessfully)]){ 
     [self.target messageSentSuccessfully]; 
    } 

    WN_POST_NOTIFICATION(kMessageSentSuccessfully,nil); 
} 

[self dismissModalViewControllerAnimated:YES]; 
} 

- (BOOL) sendMailOnAnotherThread:(CTCoreMessage*)message { 


BOOL success = YES; 

BOOL auth = YES; 
BOOL tls = YES; 

@try { 
    [CTSMTPConnection sendMessage:message server:GMAIL_SERVER username:username 
         password:password port:GMAIL_PORT_Number useTLS:tls useAuth:auth]; 
} 
@catch (NSException * e) { 
    //Msg failed to send; 
    success = FALSE; 
} 
return success;  
} 

- (void)showWaitingView { 
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; 

CGRect frame = CGRectMake(90, 190, 32, 32); 
UIActivityIndicatorView* progressInd = [[UIActivityIndicatorView alloc] initWithFrame:frame]; 
[progressInd startAnimating]; 
progressInd.activityIndicatorViewStyle = UIActivityIndicatorViewStyleWhiteLarge; 

frame = CGRectMake(130, 193, 140, 30); 
UILabel *waitingLable = [[UILabel alloc] initWithFrame:frame]; 
waitingLable.text = @"Processing..."; 
waitingLable.textColor = [UIColor whiteColor]; 
waitingLable.font = [UIFont systemFontOfSize:20];; 
waitingLable.backgroundColor = [UIColor clearColor]; 
frame = [[UIScreen mainScreen] applicationFrame]; 
UIView *theView = [[UIView alloc] initWithFrame:frame]; 
theView.backgroundColor = [UIColor blackColor]; 
theView.alpha = 0.7; 
theView.tag = 999; 
[theView addSubview:progressInd]; 
[theView addSubview:waitingLable]; 

[progressInd release]; 
[waitingLable release]; 

[window addSubview:[theView autorelease]]; 
[window bringSubviewToFront:theView]; 
[pool drain]; 
} 

- (void)removeWaitingView { 
UIView *v = [window viewWithTag:999]; 
if(v) [v removeFromSuperview]; 

} 
+0

您是否將UI更新移動到後端線程? – 2011-05-30 06:25:12

+0

否我已經將UI更新移動到不在後臺線程中的另一個線程,並且按預期工作。首先,它給了我NSAutoreleas池泄漏的警告,但是當我將代碼放入autorelease池時,警告不在我已經在gdb中測試過的地方。 – 2011-05-30 06:39:28

+0

有很多地方明確喊UIKit更新只能在主線程中完成,就像[this]一樣(http://developer.apple.com/library/ios/#documentation/uikit/reference/UIKit_Framework/Introduction/ Introduction.html)。所以有可能會在稍後突破。 – 2011-05-30 06:48:18

1

是的。您需要返回到運行循環才能更新UI。因此,最好在主線程中顯示等待視圖,在後臺線程中發送郵件,然後再次隱藏並刪除主要等待視圖。您應該只從主線程更新UI。您可以使用performSelectorInBackground和performSelectorOnMainThread以簡單方式執行此操作,而無需手動創建線程。您也可以使用dispatch_async這樣的:

//show waiting view 
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ 
    //prepare mail here 

    dispatch_async(dispatch_get_main_queue(), ^{ 
     //send mail 
     //hide waiting view 
    }); 
}); 
+0

這不是因爲它應該是。我現在已經更新了我的代碼,請建議如何執行此操作。 – 2011-05-27 12:20:58

+0

另外我無法在後臺線程中發送郵件。我應該使用NSOPeration Queue嗎? – 2011-05-27 12:24:15

+0

來自apple文檔: performSelector:方法等同於直接向接收方發送aSelector消息。 所以你現在還沒有正在做任何多線程。我建議改變performSelector:@selector(prepareAndSendMail)來執行SelectorInBackground:然後請給出關於失敗的更多細節。 – 2011-05-27 15:38:29

0

因爲你是在主線程上執行prepareAndSendMailWNAppDelegate performSelectorOnMainThread:@selector(showWaitingView) withObject:nil waitUntilDone:NO];將在當前運行的循環已經結束到那時你會發送郵件後打電話showWaitingView。將waitUntilDone:設置爲YES將在您打算時顯示等待視圖。

+0

將該標誌設置爲yes仍然不起作用。 – 2011-05-27 13:36:05

+0

有沒有在後臺執行的原因?奇怪的是,因爲我們在主線程中,所以可以簡化爲'[WNAppDelegate showWaitingView];' – 2011-05-27 20:43:23

+0

是的,因爲使用smtp發送郵件不能在後臺執行。 – 2011-05-28 03:09:28