这一节我们为YDChat添加对Roster的支持,实现好友的添加和显示功能。XMPP框架在XMPPRoster类中已经支持了对roster的处理。在YDAppDelegate的setupStream方法中,我们已经构造并配置了一个xmppRoster的实例。XMPP框架还通过XMPPRosterCoreDataStorage类支持我们将好友列表写入内存、core data或者自定义的存储机制中。
autoFetchRoster标示应用程序在连接到服务器后会自动请求好友列表。
autoAcceptKnownPresenceSubscriptionRequests用于让应用程序只获取在线好友的信息,因为实际的好友列表可能很大,而用户只关心在线的好友。
// Setup roster
//
// The XMPPRoster handles the xmpp protocol stuff related to the roster.
// The storage for the roster is abstracted.
// So you can use any storage mechanism you want.
// You can store it all in memory, or use core data and store it on disk, or use core data with an in-memory store,
// or setup your own using raw SQLite, or create your own storage mechanism.
// You can do it however you like! It's your application.
// But you do need to provide the roster with some storage facility.
self.xmppRosterStorage = [[XMPPRosterCoreDataStorage alloc] init];
// xmppRosterStorage = [[XMPPRosterCoreDataStorage alloc] initWithInMemoryStore];
self.xmppRoster = [[XMPPRoster alloc] initWithRosterStorage:self.xmppRosterStorage];
self.xmppRoster.autoFetchRoster = YES;
self.xmppRoster.autoAcceptKnownPresenceSubscriptionRequests = YES;
显示好友列表
实现YDContactsViewController,继承于YDBaseViewController。这个类中,有一个UITableView用于显示好友列表。
#import "YDBaseViewController.h"
@interface YDContactsViewController : YDBaseViewController
@end
声明遵循以下代理协议
#import "YDContactsViewController.h"
#import <CoreData/CoreData.h>
#import "YDAppDelegate.h"
#import "DDLog.h"
@interface YDContactsViewController ()<NSFetchedResultsControllerDelegate,UITableViewDataSource,UITableViewDelegate,UIAlertViewDelegate>
{
NSFetchedResultsController *fetchedResultsController;
}
@property (nonatomic,strong) UITableView *mtableView;
@end
实现viewDidLoad,创建UITableView并设置自己是其data source和代理
- (void)viewDidLoad
{
[super viewDidLoad];
self.view.backgroundColor=[UIColor whiteColor];
self.mtableView = [[UITableView alloc] initWithFrame:CGRectMake(0,86,ScreenWidth,ScreenHeight - 86-40) style:UITableViewStylePlain];
self.mtableView .delegate=self;
self.mtableView .dataSource=self;
self.mtableView .rowHeight=38.0;
self.mtableView .separatorStyle=UITableViewCellSeparatorStyleNone;
self.mtableView .backgroundColor = [UIColor clearColor];
[self.view addSubview:self.mtableView];
}
实现fetchResultController,用于从XMPPUserCoreDataStorage获取数据
- (NSFetchedResultsController *)fetchedResultsController
{
if (fetchedResultsController == nil)
{
NSManagedObjectContext *moc = [[self appDelegate] managedObjectContext_roster];
NSEntityDescription *entity = [NSEntityDescription entityForName:@"XMPPUserCoreDataStorageObject"
inManagedObjectContext:moc];
NSSortDescriptor *sd1 = [[NSSortDescriptor alloc] initWithKey:@"sectionNum" ascending:YES];
NSSortDescriptor *sd2 = [[NSSortDescriptor alloc] initWithKey:@"displayName" ascending:YES];
NSArray *sortDescriptors = [NSArray arrayWithObjects:sd1, sd2, nil];
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
[fetchRequest setEntity:entity];
[fetchRequest setSortDescriptors:sortDescriptors];
[fetchRequest setFetchBatchSize:10];
fetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest
managedObjectContext:moc
sectionNameKeyPath:@"sectionNum"
cacheName:nil];
[fetchedResultsController setDelegate:self];
NSError *error = nil;
if (![fetchedResultsController performFetch:&error])
{
DDLogError(@"Error performing fetch: %@", error);
}
}
return fetchedResultsController;
}
- (void)controllerDidChangeContent:(NSFetchedResultsController *)controller
{
[self.mtableView reloadData];
}
tableView相关的方法:
#pragma mark UITableViewCell helpers
- (void)configurePhotoForCell:(UITableViewCell *)cell user:(XMPPUserCoreDataStorageObject *)user
{
// Our xmppRosterStorage will cache photos as they arrive from the xmppvCardAvatarModule.
// We only need to ask the avatar module for a photo, if the roster doesn't have it.
if (user.photo != nil)
{
cell.imageView.image = user.photo;
}
else
{
NSData *photoData = [[[self appDelegate] xmppvCardAvatarModule] photoDataForJID:user.jid];
if (photoData != nil)
cell.imageView.image = [UIImage imageWithData:photoData];
else
cell.imageView.image = [UIImage imageNamed:@"emptyavatar"];
}
}
#pragma mark UITableView
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return [[[self fetchedResultsController] sections] count];
}
- (NSString *)tableView:(UITableView *)sender titleForHeaderInSection:(NSInteger)sectionIndex
{
NSArray *sections = [[self fetchedResultsController] sections];
if (sectionIndex < [sections count])
{
id <NSFetchedResultsSectionInfo> sectionInfo = [sections objectAtIndex:sectionIndex];
int section = [sectionInfo.name intValue];
switch (section)
{
case 0 : return @"Available";
case 1 : return @"Away";
default : return @"Offline";
}
}
return @"";
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)sectionIndex
{
NSArray *sections = [[self fetchedResultsController] sections];
if (sectionIndex < [sections count])
{
id <NSFetchedResultsSectionInfo> sectionInfo = [sections objectAtIndex:sectionIndex];
return sectionInfo.numberOfObjects;
}
return 0;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = @"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil)
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:CellIdentifier];
}
XMPPUserCoreDataStorageObject *user = [[self fetchedResultsController] objectAtIndexPath:indexPath];
cell.textLabel.text = user.displayName;
[self configurePhotoForCell:cell user:user];
return cell;
}
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[tableView deselectRowAtIndexPath:indexPath animated:YES];
//Get our contact record
XMPPUserCoreDataStorageObject *user = [[self fetchedResultsController] objectAtIndexPath:indexPath];
DDLogInfo(@"user %@",user.jidStr);
}
viewWillDisappear
- (void)viewWillDisappear:(BOOL)animated
{
// do not disconnect to the sever when exit from contacts view controller
//[[self appDelegate] disconnect];
[[[self appDelegate] xmppvCardTempModule] removeDelegate:self];
[super viewWillDisappear:animated];
}
此外还需要修改YDAppDelegate函数,实现通过点击侧边栏在HomeView和ContactsView之间的切换:
-(void)leftMenuSelectionItemClick:(YDMenuItem *)item
{
if ([item.controllerTAG length]>0)
{
[self.container setMenuState:YDSLideMenuStateClosed];
if ([item.controllerTAG isEqualToString:kMenuHomeTag])
{
//allocate the View Controller
if (homeViewController == nil)
{
homeViewController = [[YDHomeViewController alloc]init];
}
[self.navigationController popViewControllerAnimated:YES];
//[self.navigationController pushViewController:homeViewController animated:YES];
}
else if ([item.controllerTAG isEqualToString:kMenuContactsTag])
{
//allocate the View Controller
contactsViewController = [[YDContactsViewController alloc]init];
[self.navigationController popViewControllerAnimated:YES];
[self.navigationController pushViewController:contactsViewController animated:YES];
}
}
}