本文主要介绍XMPPFramework下花名册的使用方法,实现的功能有:获取好友列表、添加好友、删除好友。
和电子名片模块一样,获取好友列表同样需要在XMPPFramework.h中启用花名册模块,并在XMPP工具类中定义成员变量,为XMPPStream添加花名册模块拓展。
XMPPFramework.h 启用花名册模块:
//花名册模块
#import "XMPPRoster.h"
#import "XMPPRosterCoreDataStorage.h"
WCXMPPTool.h中定义成员变量:
//花名册模块
@property (nonatomic, strong, readonly) XMPPRoster *roster;
//花名册数据存储
@property (nonatomic, strong, readonly) XMPPRosterCoreDataStorage *rosterStorage;
WCXMPPTool.m,在setupStream方法中 为XMPPStream添加花名册模块拓展:
// 3.添加花名册模块
if (_rosterStorage == nil) {
_rosterStorage = [[XMPPRosterCoreDataStorage alloc] init];
_roster = [[XMPPRoster alloc] initWithRosterStorage:_rosterStorage];
[_roster activate:_xmppStream];
}
程序从服务器中获取到好友列表后,会把数据保存到本地并生成一个sqlite文件。
另外,在上一节没讲的是,程序退出后要释放相应的资源,在WCXMPPTool中增加以下内容:
- (void)teardownStream
{
//移除代理
[_xmppStream removeDelegate:self];
//取消模块
[_vCard deactivate];
[_avatar deactivate];
[_roster deactivate];
//断开连接
[_xmppStream disconnect];
//清空资源
_rosterStorage = nil;
_roster = nil;
_vCardStorage = nil;
_vCard = nil;
_avatar = nil;
_xmppStream = nil;
}
- (void)dealloc
{
[self teardownStream];
}
@interface WCContactViewController () <NSFetchedResultsControllerDelegate>{
NSFetchedResultsController *_resultContr;
}
@property (nonatomic, strong) NSArray *users;
@end
NSFetchedResultsController,官方解释是可以有效地管理从Core Data读取到的提供给UITableView对象的数据。
使用方法分为3步:
1. 配置一个request,指定要查询的数据库表
2. 至少为获取到的数据设置一个排序方法
3. 可以为数据设置过滤条件
除此之外,它还提供以下两个功能:
1. 监听和它关联的上下文(NSManagedObjectContext)的改变,并报告这些改变
2. 缓存结果,重新显示相同的数据的时候不需要再获取一遍
/** * 好友列表加载 */
- (void)loadUsers
{
//显示好友数据(保存在XMPPRoster.sqlite)
//1.上下文,关联XMPPRoster.sqlite
NSManagedObjectContext *rosterContext = [[WCXMPPTool sharedWCXMPPTool].rosterStorage mainThreadManagedObjectContext];
//2.请求查询哪张表
NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:@"XMPPUserCoreDataStorageObject"];
//设置排序
NSSortDescriptor *sort = [NSSortDescriptor sortDescriptorWithKey:@"displayName" ascending:YES];
request.sortDescriptors = @[sort];
//过滤没有添加成功的好友
//语法和sql一样
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"subscription != %@", @"none"];
request.predicate = predicate;
//3.执行请求
//3.1创建结果控制器
_resultContr = [[NSFetchedResultsController alloc] initWithFetchRequest:request managedObjectContext:rosterContext sectionNameKeyPath:nil cacheName:nil];
_resultContr.delegate = self;
//3.2执行
NSError *error = nil;
[_resultContr performFetch:&error];
}
#pragma mark - Table view data source
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return _resultContr.fetchedObjects.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *ID = @"users";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:ID];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:ID];
}
XMPPUserCoreDataStorageObject *user = _resultContr.fetchedObjects[indexPath.row];
cell.textLabel.text = user.displayName;
//标志用户是否在线
//0:在线 1:离开 2:离线
ZHLog(@"%@ 在线状态:%@", user.displayName, user.sectionNum);
switch ([user.sectionNum integerValue]) {
case 0:
cell.detailTextLabel.text = @"在线";
break;
case 1:
cell.detailTextLabel.text = @"离开";
break;
case 2:
cell.detailTextLabel.text = @"离线";
break;
default:
cell.detailTextLabel.text = @"其它";
break;
}
//显示好友头像,一般情况下,程序启动时没有头像
if (user.photo) {
cell.imageView.image = user.photo;
}else {
NSData *data = [[WCXMPPTool sharedWCXMPPTool].avatar photoDataForJID:user.jid];
cell.imageView.image = [UIImage imageWithData:data];
}
#pragma mark 结果控制器代理方法
#pragma mark 数据库内容改变
- (void)controllerDidChangeContent:(NSFetchedResultsController *)controller
{
[self.tableView reloadData];
}
#pragma mark 实现此方法,左移cell就会出现删除按钮
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
{
XMPPUserCoreDataStorageObject *user = _resultContr.fetchedObjects[indexPath.row];
if (editingStyle == UITableViewCellEditingStyleDelete) {
[[WCXMPPTool sharedWCXMPPTool].roster removeUser:user.jid];
}
}
/** * 添加好友 */
- (IBAction)addContactBtnClick:(id)sender {
NSString *user = self.textField.text;
//不能添加自己为好友
if ([user isEqualToString:[WCUser shareUser].loginAccount]) {
[self showAlert:@"不能添加自己为好友!"];
return;
}
//已存在的好友无需添加
XMPPJID *userJid = [XMPPJID jidWithUser:user domain:[WCUser shareUser].domain resource:nil];
BOOL isUserExiests = [[WCXMPPTool sharedWCXMPPTool].rosterStorage userExistsWithJID:userJid xmppStream:[WCXMPPTool sharedWCXMPPTool].xmppStream];
if (isUserExiests) {
[self showAlert:@"好友已经存在!"];
}
//subscribe是订阅的意思
[[WCXMPPTool sharedWCXMPPTool].roster subscribePresenceToUser:userJid];
}
- (void)showAlert:(NSString *)message
{
UIAlertView *av = [[UIAlertView alloc] initWithTitle:@"提示" message:message delegate:nil cancelButtonTitle:@"知道了" otherButtonTitles:nil, nil];
[av show];
}
聊天的功能在下一节讲,这里先把跳转到聊天界面的功能的代码贴上来
#pragma mark 点中进入聊天界面
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
//把要聊天的好友的jid传过去
XMPPJID *friendJid = [_resultContr.fetchedObjects[indexPath.row] jid];
[self performSegueWithIdentifier:@"toChatVcSegue" sender:friendJid];
}
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
id destVc = segue.destinationViewController;
if ([destVc isKindOfClass:[WCChatViewController class]]) {
WCChatViewController *chatVc = destVc;
chatVc.friendJid = sender;
}
}
以下代码写在XMPPTool类里面。
为roster设置几个属性
//给xmppRoster添加代理
[_roster addDelegate:self delegateQueue:dispatch_get_main_queue()];
//设置好友同步策略,XMPP一旦连接成功,同步好友到本地
[_roster setAutoFetchRoster:YES];
//关掉自动接收好友请求,默认开启自动同意
[_roster setAutoAcceptKnownPresenceSubscriptionRequests:NO];
添加autoPing模块
@property (nonatomic, strong, readonly) XMPPAutoPing *xmppAutoPing;
@property (nonatomic, strong) XMPPPresence *receivePresence;
//6.autoPing模块
_xmppAutoPing = [[XMPPAutoPing alloc] init];
[_xmppAutoPing activate:_xmppStream];
[_xmppAutoPing setPingInterval:1000];
//来自普通的用户的请求一样会响应
[_xmppAutoPing setRespondsToQueries:YES];
#pragma mark =====好友添加模块=======
/** 收到出席订阅请求(代表对方想添加自己为好友) */
- (void)xmppRoster:(XMPPRoster *)sender didReceivePresenceSubscriptionRequest:(XMPPPresence *)presence
{
//添加好友一定会订阅对方,但是接受订阅不一定要添加对方为好友
self.receivePresence = presence;
//提示用户信息
NSString *userName = presence.from.bare;
NSString *message = [NSString stringWithFormat:@"【%@】想加你为好友", userName];
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:nil message:message delegate:self cancelButtonTitle:@"拒绝" otherButtonTitles:@"同意", nil];
[alertView show];
}
#pragma mark - 监听alert点击事件
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
if (buttonIndex == 0) { //拒绝
[self.roster rejectPresenceSubscriptionRequestFrom:_receivePresence.from];
} else { //接受
[self.roster acceptPresenceSubscriptionRequestFrom:_receivePresence.from andAddToRoster:YES];
}
}
- (void)xmppRoster:(XMPPRoster *)sender didReceiveRosterPush:(XMPPIQ *)iq { ODLog(@"发送好友添加请求-->%@", iq); } #pragma mark 互为好友 - (void)xmppRoster:(XMPPRoster *)sender didReceiveRosterItem:(DDXMLElement *)item { ODLog(@"互为好友-->%@, %@", item, [item attributeStringValueForName:@"jid"]); }
打印结果:
以上。