1. 程式人生 > >使用MailCore建立iOS郵件客戶端(二)

使用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

:1to:0 withFetchAttributes:CTFetchAttrEnvelope]];// |

[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了。