XMPPFramework开发(三):好友列表

</br>

搞事前言


面前无异首博客,我们本着XMPPFramework的报到注册功能与逻辑做了详尽的说明,用户登录就后,我们得做的哪怕是获取到目前账号的挚友列表和个人信息,今天立马同一首博客就是本着忘年交列表的连带逻辑和代理方来开一下执教说明.我们事先看看SDChat中之好友列表示意图.

</br>

XMPPFramework中好友关系说明说


当XMPPFramework中呢,好友关系是好透过订阅来促成之,也就是说A与B相互订阅,那么A与B就是好友了,如果A只是订阅了B,B没有订阅A,那么我们尽管说A与B两者不是好友,当然了,我在实质上过程被打好友添加的逻辑还是比较多之,这里用了解A与B相互订阅(openfire服务器中订阅状态呢both,当然矣,订阅状态吧出from和to,这样的为算是好友.具体情况后面会详细说明),那么A与B就是好友这一个逻辑即可.

</br>

知音列表获取流程.


当用户登录成功以后,我们开的极关键的一个模块就是加载好友列表模块.那么好友加载模块的总体流程是怎么的呢?我们先行押一个SDChat好友列表的流程图,帮助我们耳熟能详好友列表在实质上过程被怎样表现的.(图片或看不清楚,请自行下载查看,谢谢.)

</br>

好友服务器数据获得代码有

XMPPFramework中好友列表的管理核心类是XMPPRoster,这个仿佛可以为此来针对好友的音获取,添加,删除等操作.在SDChat中,我们将XMPPRoster声明为SDXmppManager的一个性对象,并且以初始化过程被激活好友模块.代码如下所示.(说明:XMPPRosterCoreDataStorage靶下存储好友数据的.)

self.rosterCoreDataStorage= [XMPPRosterCoreDataStorage sharedInstance];

self.roster = [[XMPPRoster alloc]initWithRosterStorage:self.rosterCoreDataStorage dispatchQueue:dispatch_get_global_queue(0, 0)];

//激活roster
[self.roster activate:self.stream];

其实好友获取是发生三三两两种植办法的,骚栋使用的凡代理方获得好友节点的.由于代理方默认的凡在签到成功以后默认就会见调用获取好友节点,但是我做页面的上需要调剂一下密友节点获取的时机,所以,我就是将XMPPRoster的机关获取好友节点功能关闭了.当然了,你可使机动获得取.这个要根据实际情形而早晚,实现代码如下所示.

self.roster.autoFetchRoster = NO;

这么在我们登录成功之后,我们要以- (void)xmppStreamDidAuthenticate:(XMPPStream *)sender本条方式吃手动调起获好友的方法.调起道吗十分简短,只待一行代码就可以.

[[SDXmppManager defaulManager].roster fetchRoster];

当我们调整起了获得好友的方式之后,我们要以在联系人列表(SDContactsVC)这个控制器中优先安装XMPPRoster对象的代理.我是在初始化就设置了代理对象.

[[SDXmppManager defaulManager].roster addDelegate:self delegateQueue:dispatch_get_main_queue()];

设置完以后代理方其实总共是出三个之,三个代理调取的实际分别是持有好友节点获取开始,每一个好友节点获取到的时段,所有好友节点获取成功后,我们可以根据实际情况来进展不同之操作.比如我们当获得开始之前初始化好友节点数组,获取了刷新页面等等,具体的老三单代理方如下所示.

//开始获取好友节点列表的时候
-(void)xmppRosterDidBeginPopulating:(XMPPRoster *)sender;

//获取每一个好友节点的时候
-(void)xmppRoster:(XMPPRoster *)sender didReceiveRosterItem:(DDXMLElement *)item;

//结束获取好友节点列表的时候
-(void)xmppRosterDidEndPopulating:(XMPPRoster *)sender;

立马是自家单独利用了后边的简单单代理方,这是生由之,因为我的密友节点数组([SDUser defaulUser].contactsArray)不欲各级一样糟糕得到都进行翻新,而且就三单代理方以事实上使用过程遭到,自动调取的次数多,比如添加完好友或者去完好友都能自行调取这三单代理方,为了不必要之辛苦,所以我只是用了背后的星星点点个代理方法.还是那句话,大家可以根据自己之实在情形自行调用不同的代办方法.

咱们先押一下SDChat中在-(void)xmppRoster:(XMPPRoster *)sender didReceiveRosterItem:(DDXMLElement *)item;骚栋都召开了什么样的操作.首先,我们得到各一个好友节点item,然后我们先行判断item节点的订阅信息subscription的价值,我们得的好友是两头互相订阅,也不怕是”subscription”属性也”both”、”from”、”to”才是我们得之好友节点.所以符合这三种情景的且是咱们需要之知心人节点,所以if的罗标准就出去了,如下代码所示.其他订阅类型不同之节点我们后面会说到实际的情况.

if ([[[item attributeForName:@"subscription"] stringValue] isEqualToString:@"both"]||[[[item attributeForName:@"subscription"] stringValue] isEqualToString:@"from"]||[[[item attributeForName:@"subscription"] stringValue] isEqualToString:@"to"]) {

}

每当罗好后,我们用做的政工就是是得到到item节点的JID信息了,这里我们仅仅待两行代码就可就了.

NSString *SJid = [[item attributeForName:@"jid"] stringValue];

XMPPJID *jid = [XMPPJID jidWithString:SJid];

无是头界面上显得好友的JID信息,还是晚显示电子名片信息,我们都急需先周历好友节点数组([SDUser defaulUser].contactsArray)判断数组中是否已存在拖欠好友信息了.这样做的来由是以-(void)xmppRoster:(XMPPRoster *)sender didReceiveRosterItem:(DDXMLElement *)item;是代理方或者对一个密友节点获取多次,如果我们不进行选择性的丰富的话,数组可能会见起好友重复的情景的,所以我们要事先判断是否留存拖欠好友信息,具体代码如下所示.(关于isDeleteFriend布尔值的留存的含义,当我们抹好友的时刻,订阅信息subscription的值可能并无是”remove”,有或是”both”,所有我们这里要加一个布尔值,后面的勾好友,我们见面详细说明的.)

BOOL isExist = NO;

for (SDContactModel *contact in self.user.contactsArray) {

       if ([contact.jid.user isEqualToString:jid.user]) {

            isExist = YES;

          }
}         

判定了是否在好友信息之后,我们就是得依据isExist这个布尔值来判定了是否要补充加多少了,添加数据经过如下代码所示,这里我是收获了知音的刺信息进行的增长,前期的口舌可一直上加JID.

if (!isExist) {
    //添加数据
    XMPPvCardTemp *vCard =  [[SDXmppManager defaulManager].vCardTempModule vCardTempForJID:jid shouldFetch:YES];

    SDContactModel *contact =[[SDContactModel alloc]init];
    contact.jid = jid;
    contact.vCard =vCard;
    contact.isAvailable = NO;

    [self.user.contactsArray addObject:contact];

}

面就由服务器获取到相知数据的核心流程了.

</br>

知音数据本地整理代码有

当我们收获好友数据好之后,我们连无是一直展现到页面及,我们得对好友数据进行整然后再展现到界面的上.我们经过-(void)xmppRosterDidEndPopulating:(XMPPRoster *)sender;此代理方来调取我们的相知数据整理方法-(void)networkingWithContactsArray;.

-(void)xmppRosterDidEndPopulating:(XMPPRoster *)sender{

    [self networkingWithContactsArray];

}

SDChat的挚友界面是相仿于微信的密友界面的,是分组展示的.所以,数据存储的整体思路是,列表的数据源是储存于一个字典当中,我们将首字母相同的JID或者是用户称存储于一个数组当中.每个key是每一个JID的首字母大写(或者是用户称的首字母大写).因为字典是无序的,那么哪些完成有序的排呢?我们得树立另外一个数组作为排序数组,同时也打在索引数组的作用.我们管字典中存有的Key放入数组中,然后排序,数据提取过程遭到我们只需要根据数组的排列顺序拿取即可.示意图如下所示.

那么我们看一下事实上代码过程中,对于字典的多少增长整理部分,首先我们如果初始化字典对象,然后我们遍历好友节点数组([SDUser defaulUser].contactsArray),取出我们需要排序的每一个主要字符串(不管是JID还是用户称).我们调用-(NSString *)transform:(NSString *)chinese这个方法回去首字母并且很写.在斯法子被我们发几乎栽情景用处理,一种植是收获字符串失败,也就是说传入的凡一个nil值,我们一直归
“#”
,另外一种是一旦首字母是数字,那么我们呢是内需返回”#”的.所以这样回去首字母所使用及之法总共就发生了三单,两只用来判定是否是屡组,一个虽说是截取并且进行字母大写的操作.三个艺术如下所示.

//截取首字母并且大写
-(NSString *)transform:(NSString *)chinese{

    if (chinese == nil ||[chinese isEqualToString:@""]) {

        return @"#";

    }

    NSMutableString *pinyin = [chinese mutableCopy];
    CFStringTransform((__bridge CFMutableStringRef)pinyin, NULL, kCFStringTransformMandarinLatin, NO);
    CFStringTransform((__bridge CFMutableStringRef)pinyin, NULL, kCFStringTransformStripCombiningMarks, NO);

    NSString *subString = [[pinyin uppercaseString] substringWithRange:NSMakeRange(0, 1)];

    if ([self isPureInt:subString] || [self isPureFloat:subString]) {

        return  @"#";
    }

    return subString;
}

//判断是否为整型:
- (BOOL)isPureInt:(NSString*)string{
    NSScanner* scan = [NSScanner scannerWithString:string];
    int val;
    return [scan scanInt:&val] && [scan isAtEnd];
}
//判断是否为浮点型:
- (BOOL)isPureFloat:(NSString*)string{
    NSScanner* scan = [NSScanner scannerWithString:string];
    float val;
    return[scan scanFloat:&val] && [scan isAtEnd];
}

那通过返回首字母,我们需要判定一下即底字典对象吃是否曾经在了改分组的往往组,如果有,那么直接存储,如果未存在,那么初始化一个数组之后,以首假名为Key,空数组为Value保存至字典中,然后还管数据存储到数组中错过.具体代码如下所示.

if (self.contactsPinyinDic[firstWord] ==nil) {

    //如果联系人字典数组中没有该分组,那么就初始化一个分组数组,然后存储.
    NSMutableArray *sectionArray =[NSMutableArray  arrayWithCapacity:16];

    [sectionArray addObject:contact];

    [self.contactsPinyinDic setValue:sectionArray forKey:firstWord];

}else{

    NSMutableArray *sectionArray =self.contactsPinyinDic[firstWord];

    [sectionArray addObject:contact];

}

增长完成以后,我们就是用对索引数组进行操作了,首先我们还是先初始化我们的索引数组,初始化的长河被,我们就将具备的key值添加到我们的数组当中去.然后我们得添加一个空字符串@"",这是为了为”新的情人”那个分组做准备的.代码如下所示.

self.indexArray = [NSMutableArray arrayWithArray:self.contactsPinyinDic.allKeys];
[self.indexArray addObject:@""];//添加一个空的字符串,用于菜单分组

接下来,我们对索引数组进行遍历排序操作.

    for (int i = 0; i<self.indexArray.count; i++) {

        for (int j = 0; j<i; j++) {

            if (self.indexArray[j]>self.indexArray[i]) {

                NSString *objString = self.indexArray[j];
                self.indexArray[j] =  self.indexArray[i];
                self.indexArray[i] = objString;

            }
        }
    }

苟在”#”,为了界面的美丽,我们管”#”放在索引数组的末尾一各类,然后,我们就算刷新我们的页面就可.

//索引数组移动#号到最后.
if ([self isIncludeWithJing]) {

    [self.indexArray removeObject:@"#"];

    [self.indexArray addObject:@"#"];
}

[self.contactsList reloadData];

这样于tableView的数据源方法中,分组个数为索引数组的因素个数self.indexArray.count;每一个section中元素的个数(除了一个分组)都是为字典中对应的各国一个value数组的单数.

下一场,我们尽管得做出开始之界面的法来了.当然矣,这样的画面需要我们开多工作的,也是咱们下一致篇博客所假设说到的,电子名片的实现.

</br>

结束


SDChat中之知心人获取之逻辑和代办方就是说到此了,这里我如果优先声明一下,SDChat中或还存在正在Bug,如果产生外问题,欢迎联系骚栋,谢谢.接下来的平篇自看当事先拿XMPPFramework电子名片的实现说一下,XMPPFramework我觉着太坑的饶是增长好友这同一片了,逻辑比较多,准备以第五首被开展讲解说明.希望大家持续关注~最后把SDChat的传递门送给大家.大家好对照着Demo来拘禁本篇博客.

–>SDChat传送门🚪

</br>

相关文章