2011-05-24 93 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