使用MailCore建立iOS郵件客戶端(二)
三、列出郵件列表
列出某個資料夾路徑(folderPath)下的所有郵件列表,如下圖所示:
程式碼如下:CTCoreAccount* acc=UIAppDelegate.account;
if (!acc || ![acc isConnected]) {
NSLog(@"連線丟失,重新連線IMAP伺服器!");
acc=openconnect();
}
CTCoreFolder *folder = [acc folderWithPath: folderPath];
messages=[[NSArrayalloc]initWithArray:[folder messagesFromSequenceNumber
[tbMailListreloadData]; 首先需要檢測連線是否丟失,如果丟失進行重連(這需要用到帳號、密碼等資訊,這些東西我們儲存在UserDefaults中)。然後用folderPath初始化CTCoreFolder物件。並呼叫CTCoreFolder物件的messagesFromSequenceNumber:withFetchAttributes:方法。這個方法會去抓取伺服器上的郵件資訊,我們在《 MailCore 快速入門指南》中進行過介紹。關鍵是第二個引數指定了抓取選項,即一個 CTFetchAttributes 列舉引數。如果抓取選項為CTFetchAttrEnvelope,則指定了我們要讀取的僅僅是郵件的信封,因為信封中包含from、to、subject、sentDate等資訊——這些資訊我們會在UITableview的單元格中列出,但不會抓取正文資訊。如果要讀取正文,需要使用CTFetchAttrBodyStructure選項。還有一種選項,是CTFetchAttrDefaultsOnly,僅抓取郵件的編號(UID)和大小。這三種選項可以進行“|”(或)運算,比如正文和信封一起抓取。
四、列出郵件正文
郵件正文可以用一個WebView顯示:
根據指定的資料夾路徑和郵件UID,我們可以載入郵件正文。程式碼如下:
-(void)loadMsgFromUID:(int)UID folderPath:(NSString*)path{ CTCoreAccount* acc=UIAppDelegate.account;
⋯⋯
CTCoreFolder* folder=[acc folderWithPath:path];
CTCoreMessage* msg=[[folder messageWithUID:UID]retain];// CTCoreMessage instancemust to be retain,otherwise crashed
assert(msg);
CTCoreAddress* from=[[msg from]anyObject];
assert(from);
NSString* sender=[from name];// just one CTCoreAddress in the from set
CGSize constraint = CGSizeMake(206, 21);
CGSize size = [sender sizeWithFont:[UIFontsystemFontOfSize:10]constrainedToSize:constraint lineBreakMode:UILineBreakModeTailTruncation];
[lbSendersetText:sender];
[lbSendersetFrame:CGRectMake(lbSender.frame.origin.x, lbSender.frame.origin.y, MAX(size.width, 40), 21)];
[btSendersetFrame:lbSender.frame];
// Subject
lbSubject.text=[msg subject];
// Sent Date
NSDate* date=[msg sentDateGMT];
if(date == nil) {
// if you couldn't get the sent date from the message, use a fake datein the distant past
date = [NSDatedistantPast];
}
NSDateFormatter*df=[[NSDateFormatteralloc]init];
df.dateFormat=@"yyyy-MM-dd HH:mm";
lbSentDate.text=[df stringFromDate:date];
[df release];
// Body
[wbBodyloadHTMLString:[selfextractBodyFromMessage:msg]
baseURL:nil];
// Attachments
[selfextractAttachmentsFromMessage:msg];}第2句的retain用的比較奇怪,也不需要你release。但你必須這樣做,否則程式會崩潰,估計是MailCore的一個記憶體洩露。接下來一些程式碼是計算from按鈕的Size——根據文字長度自動計算按鈕size。最後呼叫extractBodyFromMessage:方法得到郵件正文載入到webview中,呼叫extractAttachmentsFromMessage:方法下載附件。這是extractBodyFromMessage:方法:-(NSString*)extractBodyFromMessage:(CTCoreMessage*)msg{
BOOL isHtml;
NSString* body=[msg bodyPreferringPlainText:&isHtml];
// NSLog(@"body:%@",[msg body]);
NSString* keyString=@"【來自網易郵箱的超大附件】";
NSScanner* scanner=[NSScannerscannerWithString:body];
[scanner setCaseSensitive:NO];
// NSCharacterSet *kippedSet=[NSCharacterSetcharacterSetWithCharactersInString:@""];
// [scannersetCharactersToBeSkipped:kippedSet];
BOOL b;
while (![scanner isAtEnd]) {
b=[scanner scanString:keyString intoString:NULL];
if (b) {
body=[body substringToIndex:[scanner scanLocation]-keyString.length];
break;
}else{
scanner.scanLocation++;
}
}
return body;
}這個方法主要是過濾掉文字中的多餘字元。比如126郵箱,會在郵件正文後面加上附件下載和預覽的連結。如果是text/plain型別的附件,還會把附件文字加在正文最後。因此我們查詢郵件正文文字,把“【來自網易郵箱的超大附件】”之後的部分統統截去。這是 extractAttachmentsFromMessage 方法:-(void)extractAttachmentsFromMessage:(CTCoreMessage*)msg{
NSArray *atts=[msg attachments];
[attachmentsremoveAllObjects];
for (CTBareAttachment* att in atts) {
CTCoreAccount* acc=UIAppDelegate.account;
if (!acc || ![acc isConnected]) {
NSLog(@"連線丟失,重新連線IMAP伺服器!");
acc=openconnect();
}
CTCoreAttachment*core_att=[att fetchFullAttachment];
core_att.charset=att.charset;
assert(core_att);
[attachmentsaddObject:core_att];
}
}這個方法主要是呼叫CTCoreAttachment的fetchFullAttachment方法從伺服器抓取附件,並把它放到一個NSMutableArray中(一個郵件可能有多個附件)。注意程式碼中core_att.charset=att.charset;一行你可能要註釋掉。CTCoreAttachment並沒有charset這個屬性。我在這裡使用是因為我修改了MailCore中的原始碼。還有一個值得注意的是webview的委託方法:- (void)webViewDidFinishLoad:(UIWebView *)webView{
float offsetY=0;
CGSize actualSize = [webView sizeThatFits:CGSizeZero];
CGRect newFrame = webView.frame;
newFrame.size.height = actualSize.height;
webView.frame = newFrame;
offsetY=newFrame.origin.y+newFrame.size.height;
lbAttachmentsCount.frame=CGRectMake(lbAttachmentsCount.frame.origin.x,
offsetY,
lbAttachmentsCount.frame.size.width,
lbAttachmentsCount.frame.size.height);
lbAttachmentsCount.text=[NSStringstringWithFormat:@"共有 %d 個附件:",attachments.count];
offsetY+=lbAttachmentsCount.frame.size.height;
int i=0;
for (CTCoreAttachment*att inattachments) {
offsetY+=8;
CGRect rect=CGRectMake(20,0,280, 37);
UIButton* btn=[UIButtonbuttonWithType:UIButtonTypeRoundedRect];
[btn setTitle:[att decodedFilename] forState:UIControlStateNormal];
btn.frame=CGRectMake(rect.origin.x, offsetY, rect.size.width, rect.size.height);
btn.tag=(NSInteger)att;
[btn addTarget:selfaction:@selector(btnAttachClick:) forControlEvents:UIControlEventTouchUpInside];
[scrollViewaddSubview:btn];
offsetY+=rect.size.height;
i++;
}
scrollView.contentSize=CGSizeMake(scrollView.contentSize.width,
offsetY);
}當webview載入完正文,我們需要根據附件的數目在webview下面新增多個附件按鈕(UIButton),並及時調整webview和scrollview的size。根據webview載入的內容,我們通過 sizeThatFits 方法即可獲得html內容載入完成後,webview實際的 size。至於新增完附件載按鈕後,我們只有用程式碼重新計算scrollview的contentsize了。