優秀的代碼是它自己最好的文檔。當你考慮要添加一個注釋時,問問自己,“如何能改進這段代碼,以讓它不需要注釋?”*
XMPP簡介
XMPP是一種基于標準通用標記語言的子集XML的協議,它繼承了在XML環境中靈活的發展性。因此,基于XMPP的應用具有超強的可擴展性。經過擴展以后的XMPP可以通過發送擴展的信息來處理用戶的需求,以及在XMPP的頂端建立如內容發布系統和基于地址的服務等應用程序。而且,XMPP包含了針對服務器端的軟件協議,使之能與另一個進行通話,這使得開發者更容易建立客戶應用程序或給一個配好系統添加功能。
XMPP協議的實現原理過程
當我們知道XMPP是一種協議的時候,我們如何通過objective-c 代碼實現XMPP協議,進而實現我們的即時通訊功能呢? 下面的圖片就是為我們做了很好的解釋.
XMPP協議的代碼實現
1.準備工作
我們做的客戶端也服務器通訊通道的實現以及數據交流,那么首先要有我們自己的服務器,當然了,在公司的好說一些,如果是個人研究技術怎么辦呢?我們可以自己搭建一個服務器或者使用leancloud這種第三方服務器,這里我給大家提供一些搭建服務器的工具,當然了,自己搭建的服務器生命比較脆弱,請大家好好愛護~還有就是leancloud也是我推薦的一種方法.
----->點擊前往LeanCloud官方網站
----->XMPP本地服務器搭建工具下載
2.OC搭建Client和連接通道
工程完成目標:
1.創建通訊通道并完成賬號密碼的登錄
2.創建通道并完成賬號的申請
3.好友列表的獲取和顯示
4.即時通訊功能的實現
首先,我們需要導入我們的所需要導入的XMPPFramework(PS:點擊打開下載,完成之后直接解壓拖到工程中??),還有手動的導入兩個庫.如下.
libxml2.tbd
libresolv.tbd
然后,我們就要配置我們的build setting頁面的設置 search paths 選添加一個字段,添加如下
/usr/include/libxml2
完成上面的設置之后 我們需要創建一個單例類XMPPManager,用它來創建通訊通道實現上面的四個功能.
XMPPManager.h中如下
#import <Foundation/Foundation.h>
#import "XMPPFramework.h"
@interface XMPPManager : NSObject
//通訊管道
@property(nonatomic,strong)XMPPStream *stream;
//和通訊錄對象很像,用來管理好友類~
@property(nonatomic,strong)XMPPRoster *roster;
//XMPP聊天消息本地化處理對象
@property(nonatomic,strong)XMPPMessageArchiving *messageArchiving;
//消息上下文對象
@property(nonatomic,strong)NSManagedObjectContext *messageContext;
+(instancetype)defaulManager;
-(void)LoginWithUserName:(NSString *)name AndPassWord:(NSString *)password;
-(void)RegiserWithUserName:(NSString *)name AndPassWord:(NSString *)password;
//與服務器斷開鏈接
-(void)disconnectWithServer;
@end
XMPPManager.h文件的解釋:
stream : 這是C和S之間的通訊通道.
roster : 這個屬性管理好友列表的一個屬性.
messageArchiving : 這個屬性用來管理本地聊天記錄的一個類
messageContext : 消息上下文對象.
+(instancetype)defaulManager:創建單例的方法
-(void)LoginWithUserName:(NSString *)name AndPassWord:(NSString *)password : 登錄的方法
-(void)RegiserWithUserName:(NSString *)name AndPassWord:(NSString *)password : 注冊新賬號的方法
-(void)disconnectWithServer; 與服務器斷開鏈接
了解完各個方法之后,我們就要在XMPPManager.m實現一下,實現如下
#import "XMPPManager.h"
//代表與服務器進行連接的類型.
typedef enum : NSUInteger {
DoLgin,
DORegiser,
} ConnetType;
@interface XMPPManager()<XMPPStreamDelegate,XMPPRosterDelegate,XMPPMessageArchivingStorage>
@property(nonatomic,strong)NSString *password;
@property(nonatomic,strong)NSString *regiserPassword;
//聲明一個屬性 記錄連接的類型
@property(nonatomic,assign)ConnetType type;
@end
@implementation XMPPManager
static XMPPManager *manager;
+(instancetype)defaulManager{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
manager = [[XMPPManager alloc]init];
});
return manager;
}
-(instancetype)init{
if (self = [super init]) {
self.stream = [[XMPPStream alloc]init];
self.stream.hostName = kHostName;
self.stream.hostPort = kHostPort;
//設置stream的代理
[self.stream addDelegate:self delegateQueue:dispatch_get_main_queue()];
//下面這一堆其實是對roster對象進行初始化.
//系統寫好的XMPP存儲對象
XMPPRosterCoreDataStorage *dataStorage = [XMPPRosterCoreDataStorage sharedInstance];
self.roster = [[XMPPRoster alloc]initWithRosterStorage:dataStorage dispatchQueue:dispatch_get_global_queue(0, 0)];
//激活roster
[self.roster activate:self.stream];
//給roster對象指定代理
[self.roster addDelegate:self delegateQueue:dispatch_get_main_queue()];
//初始化聊天記錄管理對象
XMPPMessageArchivingCoreDataStorage *messageArchivingCoreDataStorage= [XMPPMessageArchivingCoreDataStorage sharedInstance];
self.messageArchiving = [[XMPPMessageArchiving alloc]initWithMessageArchivingStorage:messageArchivingCoreDataStorage dispatchQueue:dispatch_get_main_queue()];
//激活管理對象
[self.messageArchiving activate:self.stream];
//設置管理對象代理
[self.messageArchiving addDelegate:self delegateQueue:dispatch_get_main_queue()];
self.messageContext = messageArchivingCoreDataStorage.mainThreadManagedObjectContext;
}
return self;
}
//與服務器的建立鏈接
-(void)connectToServerWintUser:(NSString *)name{
if ([self.stream isConnected]) {
[self.stream disconnect];
}
//jid jabberID,是基于jabber協議的由用戶名生成的唯一ID
self.stream.myJID = [XMPPJID jidWithUser:name domain:kDomin resource:kResource];
NSError *error = nil;
//與服務器建立鏈接.
[self.stream connectWithTimeout:30.0f error:&error];
if (error != nil) {
@throw [NSException exceptionWithName:@"CQ_Error" reason:@"與服務器建立連接失敗,請查看代碼" userInfo:nil];
}
}
//與服務器斷開鏈接
-(void)disconnectWithServer{
[self.stream disconnect];
}
-(void)LoginWithUserName:(NSString *)name AndPassWord:(NSString *)password{
self.password = password;
self.type = DoLgin;
[self connectToServerWintUser:name];
}
//與服務器建立連接
-(void)xmppStreamDidConnect:(XMPPStream *)sender{
NSLog(@"與服務器建立鏈接正常");
//與服務器進行登錄認證
NSError *error = nil;
switch (self.type) {
case DoLgin:
[self.stream authenticateWithPassword:self.password error:&error];
if (error != nil) {
NSLog(@"認證過程出錯!");
}
break;
case DORegiser:
[self.stream registerWithPassword:self.regiserPassword error:&error];
if (error != nil) {
NSLog(@"注冊過程出錯!");
}
break;
default:
break;
}
}
-(void)xmppStreamConnectDidTimeout:(XMPPStream *)sender{
@throw [NSException exceptionWithName:@"CQ_Error" reason:@"與服務器建立連接超時,請查看代碼" userInfo:nil];
}
-(void)RegiserWithUserName:(NSString *)name AndPassWord:(NSString *)password{
self.type = DORegiser;
self.regiserPassword = password;
[self connectToServerWintUser:name];
}
看完了上面的代碼,連我自己都覺得亂亂的,所以 我們一個功能一個功能看這些代碼的實現原理,
登錄功能
我們想要登錄我們的服務器,首先要有我們的賬號和密碼,然后我們就需要建立通道
(a) defaulManager
創建單例這個方法中就是創建了我們的單例.
(b) init
初始化這個方法中我們需要對我們的通訊管道屬性stream進行初始化一下,設置stream服務器IP地址和服務器端口,還有就是設置stream的代理對象.實現XMPPStreamDelegate協議方法.這里設置代理對象的方法不同于以前,這里是使用runtime設計模式可以為stream設置多個代理對象.
(c) LoginWithUserName:(NSString )name AndPassWord:(NSString )password
這個方法中首先我們需要保存我們的密碼,用于傳值到下一個方法中.self.type = DoLgin;這句代碼有作何解釋呢?因為不管是登錄和注冊,我們都要與我們的服務器創建聯系,那么服務器是如何知道我們是創建的什么聯系的呢?就是通過這句代碼實現的,當然了,現在你可能聽得糊涂,當看到下面的方法的時候你就明白了.[self connectToServerWintUser:name];這句代碼就是要創建于服務器之間的聯系.這時候,賬號name就通過參數的形式傳到了connectToServerWintUser這個函數,而password通過屬性的傳值到xmppStreamDidConnect(當完成通道的建立的時候執行的代理方法).
(d) connectToServerWintUser
[self.stream disconnect];這句代碼就是讓客戶端斷開連接通道,綜合上面來看,當我們已經存在的連接的通道的時候,我們就會讓通道斷開,這是為什么呢?因為C與S之間的通道只能創建一條,當我們重復創建的時候,就會導致我們的程序崩潰.所以我們要保障我們的通道是只有一條的. [self.stream connectWithTimeout:30.0f error:&error];這句代碼就是我們創建通道,當然了等待時間是30秒.
(e)xmppStreamDidConnect
這是一個代理的方法,當我們完成通道的創建之后,我們就會調用這個方法,在這個代理方法中我們需要做的就是對我們的密碼進行驗證.[self.stream authenticateWithPassword:self.password error:&error];這就是登錄驗證我們的密碼.驗證成功之后就會調用-(void)xmppStreamDidAuthenticate:(XMPPStream *)sender這個代理方法,驗證失敗就會調用-(void)xmppStream:(XMPPStream *)sender didNotAuthenticate:(DDXMLElement *)error 這個代理方法,當然了,這兩個方法是寫在我們的登錄頁面的,因為我們需要對使用者有個用戶的交互不是?比如彈出一個彈窗.提醒一下用戶.xmppStreamDidConnect不管是注冊和登錄都會調用,我們怎么區分呢?我們現在.m文件的頂部設置了一個枚舉值,通過枚舉值的值判斷我們所需要的操作.
(f)xmppStreamConnectDidTimeout
這個方法就是說,當我們與服務器建立連接超時的時候會進行的操作.@throw [NSException exceptionWithName:@"CQ_Error" reason:@"與服務器建立連接超時,請查看代碼" userInfo:nil];是我們手動的拋出一個異常.
注冊功能
注冊功能與登錄功能在實現上是相似的,下面的屬性就是區別的開始.
@property(nonatomic,strong)NSString *password;
@property(nonatomic,strong)NSString *regiserPassword;
xmppStreamDidConnect
在這個方法中,我們需要對我們的注冊方法與登錄方法分別開來. [self.stream registerWithPassword:self.regiserPassword error:&error];這個方法就是我們把注冊的密碼傳到服務器上保存的方法.當然了,當我們注冊成功的時候,就會調動-(void)xmppStreamDidRegister:(XMPPStream *)sender這個協議方法,當注冊不成功的時候,我們就會調用-(void)xmppStream:(XMPPStream *)sender didNotRegister:(DDXMLElement *)error這個方法.這里我們也要拍給我們的用戶一些交互,讓我們用戶知道自己注冊的結果.
好友列表功能
在XMPPManager.m文件中,我們需要做的就是在 *** init *** 方法中對管理好友列表的roster對象進行一下初始化并且制定代理,這里需要注意一個地方,當我們設置roster的初始化的時候,我們需要使用 *** dispatch_get_global_queue(0, 0) ***全局線程,不能使用主線程,原因是如果使用主線程會出現一些莫名其妙的Bug. [self.roster activate:self.stream]; 激活roster的意思就是給roster可以通過stream通道的權限..(PS:大白話 ??)
在我們的好友列表頁面中,首先我們需要確定他是一個UITableViewController,然后我們需要從我們的服務器拿到我們的好友的列表數組.通道stream連接在我們的登錄的時候已經完成了,所以我們不需要再管理通道了,我們需要在好友列表的控制器中實現XMPPRosterDelegate的代理方法來獲取到我們的好友列表.代碼如下
在MainTableViewController.m中
#import "MainTableViewController.h"
#import "XMPPManager.h"
#import "ChatTableViewController.h"
@interface MainTableViewController ()<XMPPRosterDelegate>
//用來存儲所有的好友信息的.
@property(nonatomic,strong)NSMutableArray *dataArray;
@end
@implementation MainTableViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.dataArray = [NSMutableArray array];
[[XMPPManager defaulManager].roster addDelegate:self delegateQueue:dispatch_get_main_queue()];
}
//roster代理方法
//開始獲取好友列表的時候
-(void)xmppRosterDidBeginPopulating:(XMPPRoster *)sender{
NSLog(@"開始獲取好友列表");
}
//結束獲取好友列表
-(void)xmppRosterDidEndPopulating:(XMPPRoster *)sender{
NSLog(@"獲取好友列表完成的時候.");
}
//獲取好友信息的時候
-(void)xmppRoster:(XMPPRoster *)sender didReceiveRosterItem:(DDXMLElement *)item{
// //將每一個好友存儲下來.
// NSLog(@"%@",[item children]);
//
// NSLog(@"%@",[item name]);
NSString *SJid = [[item attributeForName:@"jid"] stringValue];
//把字符串類型的JID轉換成XMPPJID
XMPPJID *jid = [XMPPJID jidWithString:SJid];
//把JID存儲到數組中,相當修改數據源
[self.dataArray addObject:jid];
//更新UI
NSIndexPath *path = [NSIndexPath indexPathForRow:self.dataArray.count-1 inSection:0];
[self.tableView insertRowsAtIndexPaths:@[path] withRowAnimation:UITableViewRowAnimationBottom];
}
#pragma mark - Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return self.dataArray.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"MainCell" forIndexPath:indexPath];
//把字符串類型的JID轉換成XMPPJID
XMPPJID *jid = self.dataArray[indexPath.row];
cell.textLabel.text = [NSString stringWithFormat:@"%@ %@ %@",jid.user,jid.resource,jid.domain];
return cell;
}
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender{
UITableViewCell *cell = (UITableViewCell *)sender;
//拿到下一步要跳轉的controller對象
ChatTableViewController *chatVC = segue.destinationViewController;
//判斷選中的cell在當前的Table中的位置
NSIndexPath *path = [self.tableView indexPathForCell:cell];
chatVC.chatToJID = self.dataArray[path.row];
}
@end
方法解釋
在上面的代碼中我們要解釋的只有兩個方法 ,一個是獲取好友信息的時候調用的
-(void)xmppRoster:(XMPPRoster *)sender didReceiveRosterItem:(DDXMLElement *)item
另外一個是我們點擊好友進入聊天頁面所需要的方法.
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
-(void)xmppRoster:(XMPPRoster *)sender didReceiveRosterItem:(DDXMLElement *)item
這個是XMPPRosterDelegate協議中代理方法,如果我們有很多的好友,這個方法會調用很多次,知道我們的好友全部遍歷完. NSString *SJid = [[item attributeForName:@"jid"] stringValue]; 和XMPPJID *jid = [XMPPJID jidWithString:SJid];這兩個方法就是當我們從服務器接到我們的數據時候,我們要先將他轉化成一下,轉成成我們所需要的數據,然后存入我們的數據源數組中.更新UI 使用的方法是[self.tableView insertRowsAtIndexPaths:@[path] withRowAnimation:UITableViewRowAnimationBottom]; 為什么使用這個方法呢?為什么不使用reloadData這個方法?因為這個代理方法會執行很多次,我們為了避免沒有必要的內存負擔,所以我們只需要更新一下我們最后一條數據就行,這樣大大減少了內存的負擔,提高了我們的工程效率.
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
這個方法是因為我使用storyboard的原因,我們為了能正確找到我們點擊對應的cell所使用的方法.傳值的時候我們需要把JID傳到聊天界面,這樣服務器就會清楚的知道我們是對誰進行聊天了.
聊天界面功能
對于聊天界面的搭建,我們也是使用到UITableViewController,邏輯是我們需要往服務器發送我們的消息,然后服務器在通過JID發送到指定的消息,發送者發送消息的時候和接收者接收到消息的時候刷新我們的UI.
那我們就先看看在XMPPManager的類中我們需要做一些什么事情吧.
在XMPPManager.h中 我們創建了兩個屬性,一個是XMPP聊天消息本地化處理對象的messageArchiving,另外一個是消息上下文對象messageContext.
在XMPPManager.m中 的init方法中,我們對這兩個屬性進行了初始化.如下
//初始化聊天記錄管理對象
XMPPMessageArchivingCoreDataStorage *messageArchivingCoreDataStorage= [XMPPMessageArchivingCoreDataStorage sharedInstance];
self.messageArchiving = [[XMPPMessageArchiving alloc]initWithMessageArchivingStorage:messageArchivingCoreDataStorage dispatchQueue:dispatch_get_main_queue()];
//激活管理對象
[self.messageArchiving activate:self.stream];
//設置管理對象代理
[self.messageArchiving addDelegate:self delegateQueue:dispatch_get_main_queue()];
self.messageContext = messageArchivingCoreDataStorage.mainThreadManagedObjectContext;
messageArchiving對象也是需要我們激活通道權限的.然后設置了代理.
在ChatTableViewController.h界面 我們需要設置一個XMPPJID對象 來接受好友列表傳來的JID值.代碼如下.
#import <UIKit/UIKit.h>
#import "XMPPManager.h"
@interface ChatTableViewController : UITableViewController
//接收好友列表傳來的JID
@property(nonatomic,strong)XMPPJID *chatToJID;
@end
在ChatTableViewController.m文件中,我們需要做的就是實現XMPPStreamDelegate的代理方法,從代理方法中實現往服務器發送數據和從服務器接收數據的操作.代碼如下
#import "ChatTableViewController.h"
@interface ChatTableViewController ()<XMPPStreamDelegate>
//存放所有的消息
@property(nonatomic,strong)NSMutableArray *messageArray;
@end
@implementation ChatTableViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.messageArray = [NSMutableArray array];
//添加代理
[[XMPPManager defaulManager].stream addDelegate:self delegateQueue:dispatch_get_main_queue()];
//更新聊天記錄信息
[self reloadMessage];
// Uncomment the following line to preserve selection between presentations.
// self.clearsSelectionOnViewWillAppear = NO;
// Uncomment the following line to display an Edit button in the navigation bar for this view controller.
// self.navigationItem.rightBarButtonItem = self.editButtonItem;
}
//展現聊天記錄
-(void)reloadMessage{
NSManagedObjectContext *context = [XMPPManager defaulManager].messageContext;
#pragma mark----直接一個 fet 下面全都出來了----
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
//這里面要填的是XMPPARChiver的coreData實例類型
NSEntityDescription *entity = [NSEntityDescription entityForName:@"XMPPMessageArchiving_Message_CoreDataObject" inManagedObjectContext:context];
[fetchRequest setEntity:entity];
// Specify criteria for filtering which objects to fetch
//對取到的數據進行過濾,傳入過濾條件.
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"streamBareJidStr == %@ AND bareJidStr == %@", [XMPPManager defaulManager].stream.myJID.bare,self.chatToJID.bare];
[fetchRequest setPredicate:predicate];
// Specify how the fetched objects should be sorted
//設置排序的關鍵字
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"timestamp"
ascending:YES];
[fetchRequest setSortDescriptors:[NSArray arrayWithObjects:sortDescriptor, nil]];
NSError *error = nil;
NSArray *fetchedObjects = [context executeFetchRequest:fetchRequest error:&error];
if (fetchedObjects == nil) {
//完成之后干什么?
NSLog(@"和此人的激情交談");
}
/********獲取和這個人所有的聊天記錄***************/
//清空聊天數組中的消息
[self.messageArray removeAllObjects];
//將新的聊天記錄添加到數組中
self.messageArray = [NSMutableArray arrayWithArray:fetchedObjects];
NSLog(@"%ld",self.messageArray.count);
//刷新UI
[self.tableView reloadData];
//將tableview直接滑動到最底部
NSIndexPath * indexpath = [NSIndexPath indexPathForRow: self.messageArray.count-1 inSection:0];
if (indexpath.row > 0) {
[self.tableView selectRowAtIndexPath:indexpath animated:YES scrollPosition:UITableViewScrollPositionBottom];
}
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#pragma mark - Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return self.messageArray.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"ChatCell" forIndexPath:indexPath];
//取到我們對應的信息
XMPPMessageArchiving_Message_CoreDataObject *message = self.messageArray[indexPath.row];
if (message.isOutgoing == YES) {
cell.detailTextLabel.text = message.body;
cell.textLabel.text = @"";
}else {
cell.textLabel.text = message.body;
cell.detailTextLabel.text = @"";
}
return cell;
}
//發送消息
- (IBAction)sendAction:(id)sender {
XMPPMessage *message = [XMPPMessage messageWithType:@"chat" to:self.chatToJID];
[message addBody:@"nice to meet you"];
//發送消息
[[XMPPManager defaulManager].stream sendElement:message];
}
-(void)xmppStream:(XMPPStream *)sender didSendMessage:(XMPPMessage *)message{
// tipWithMessage(@"消息發送成功!");
[self reloadMessage];
}
-(void)xmppStream:(XMPPStream *)sender didFailToSendMessage:(XMPPMessage *)message error:(NSError *)error{
tipWithMessage(@"消息發送失敗");
}
-(void)xmppStream:(XMPPStream *)sender didReceiveMessage:(XMPPMessage *)message{
[self reloadMessage];
}
@end
頁面的邏輯:
當我們進入聊天界面的時候,我們會先調用reloadMessage這個方法,從服務器下載當前用戶與這個JID的聊天記錄,當我們點擊發送消息的時候,我們就會調用sendAction這個方法,發送到服務器上去,當我們發送成功后調用didSendMessage這個協議方法,然后在這協議方法中調用reloadMessage這個方法重新從服務器下載新的聊天記錄并且刷新UI,然后服務器上有當前用戶新的消息的時候,就會調用didReceiveMessage這個代理方法,我們只需要在這個方法中再次調用reloadMessage方法就可.(PS:因為我用的是storyboard 所有有些地方會有所不同??)
方法解釋:
-(void)reloadMessage
這個方法是整個聊天界面的核心.我們在這里面做的就是從服務器下載我們的數據.當我們下載完數據的時候,就要把我們數據源數組中所有的元素清空,然后將所有從服務器中下載的元素添加到我們的數組中.然后刷新我們的UI,當我一刷新之后tableView就會重頭開始了,所以我們設置讓最后一個cell顯示在屏幕上.還有就是下面的一段代碼,這是我們先前寫好的,我們需要敲出 *** fetch *** 就會給我們提示,是不是很簡答??? 這段代碼就是從網上下載我們所需要的數據.當然了,我們需要使用謂詞對這些數據進行過濾.過濾后的數據才是我們所需要的數據.
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
//這里面要填的是XMPPARChiver的coreData實例類型
NSEntityDescription *entity = [NSEntityDescription entityForName:@"XMPPMessageArchiving_Message_CoreDataObject" inManagedObjectContext:context];
[fetchRequest setEntity:entity];
// Specify criteria for filtering which objects to fetch
//對取到的數據進行過濾,傳入過濾條件.
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"streamBareJidStr == %@ AND bareJidStr == %@", [XMPPManager defaulManager].stream.myJID.bare,self.chatToJID.bare];
[fetchRequest setPredicate:predicate];
// Specify how the fetched objects should be sorted
//設置排序的關鍵字
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"timestamp"
ascending:YES];
[fetchRequest setSortDescriptors:[NSArray arrayWithObjects:sortDescriptor, nil]];
NSError *error = nil;
NSArray *fetchedObjects = [context executeFetchRequest:fetchRequest error:&error];
if (fetchedObjects == nil) {
//完成之后干什么?
NSLog(@"和此人的激情交談");
}
XMPP協議實現即時通訊的過程大體就是這樣了,當然了,我還有一些功能沒有完善,比如添加好友的功能.這將在后期進行再次的完善.謝謝大家的查看..
--->XMPP的Demo資源下載
在Demo拿到手的時候,我們首先要對我們的服務器IP進行設置.在XMPPConfig.h文件中設置服務器相關信息!!!