iOS 列表页面实时刷新解决方案

news2025/2/21 4:41:16

iOS 列表页面实时刷新解决方案

一、背景介绍

1.1 问题的出现

客户要求APP客户端每次切换Tab,都需要从服务器去获取最新的数据,所以每次切换Tab,客户端都会去主动刷新接口,以获取最新的数据。但是实际发现,每次切换Tab都去刷新,从用户体验上感觉刷新太频繁了;从性能上体验,没有数据更新也去频繁的请求接口,很消耗网络资源。于是,客户针对这一情况,提出了新的需求:当服务器有数据更新的时候,此时客户端去主动刷新列表接口以获取最新的数据,否则不需要客户端主动去请求接口,直接显示上一次从服务器请求的数据。这样就既做到了用户每次可以看到最新的数据,而且不影响用户体验和性能。

1.2 问题的解决方案

要实现列表做到服务器有数据更新时去主动请求接口,没有数据更新时则不请求接口,关键是要知道服务器什么时候数据更新了,需要服务器主动告知客户端某个列表的接口有数据更新了,当用户切换到此列表时,需要客户端主动去请求接口,获取最新的数据。要实现这一功能,采用websocket是最合适的。websocket能保持服务器和客户端的通信,当服务器有数据更新了,通过websocket告知用户需要刷新列表了。

二、WebSocket的介绍

WebSocket 是 HTML5 一种新的协议。它实现了浏览器与服务器全双工通信,能更好的节省服务器资源和带宽并达到实时通讯。

WebSocket工作原理

  1. 第一步:客户端连接websocket(连接地址 ws://…)

  2. 第二步:服务器向客户端发送心跳包。
    如果客户端能收到服务器发送的心跳包,则表明websocket连接成功。
    只要客户端不断开websocket,就能一直收到服务器发送的心跳包,如果客户端收不到心跳包了,则说明已经断开了连接,此时需要客户端重新去连接websocket。心跳包的存在,其实就是为了监测websocket是否断开连接了。

  3. 第三步:服务器主动推送消息给客户端,客户端根据具体的需求去处理业务逻辑。

  4. 第四步:断开websocket连接。

    当用户退出登录,或者是App退到了后台,此时则需要主动断开websocket,以减少服务器性能的损耗。

以上,就是websocket的工作原理。

三、WebSocket的实际运用

WebSocket的工具类网上有很多,从网上下载一个websocet连接和收发消息的工具类即可。

iOS WebSocket 工具类下载地址:https://www.jianshu.com/p/821b777555d3

3.1 客户端连接websocket

- (void)webSocketLogin
{
     //请更换websocket连接地址
    NSString *url = @"ws://121.40.165.18:8800";
    [[SocketRocketUtility instance] SRWebSocketOpenWithURLString:url];
}

连接成功之后,可以通过如下方法,收到服务器推送过来的websocket消息:

- (void)webSocket:(SRWebSocket *)webSocket didReceiveMessage:(id)message  {
    if (webSocket == self.socket) {
        NSLog(@"************************** socket收到数据了************************** ");
        NSLog(@"message:%@", message);
    }
}

打印日志如下:

************************** socket 连接成功************************** 
message:{"type":"welcome"} //websocket连接成功的提示
message:{"type":"ping","message":1650606091} //心跳包
message:{"type":"ping","message":1650606094} //心跳包
message:{"type":"ping","message":1650606097} //心跳包
...

Websocket连接辅助测试网站:http://www.websocket-test.com/

3.2 判断是否自动刷新的思路

比如,模拟 列表页/关注 列表接口的数据更新,服务器会通过websocket向客户端推送如下消息:

{"message":{"type":"refresh_list", "list_key":"列表/关注","timestamp":1669097371}}

这里主要是通过当前数据更新的时间,与上一次接口刷新的时间对比,然后判断是否需要刷新某个列表的接口。根据接口文档提供的需要自动刷新的列表接口有:

["列表页/关注", "列表页/推荐", "列表页/热点", "列表页/问答"]

3.3 具体实现

大概讲一下我的思路:

  1. 定义一个全局的字典;
  2. 以接口名 (“列表页/关注”)为key,timestamp为value,保存在全局的字典中;
  3. 每刷新成功一次列表接口,将全局字典中接口名对应的值更新一次;
  4. 每次收到websocket数据更新消息,将全局字典中接口名对应的值更新一次;
  5. 用户进入某个列表页面时,取当前系统的时间和全局字典中这个接口对应的最后刷新时间对比,决定是否需要刷新页面。
3.3.1 定义一个全局的字典
#import "ApiNameData.h"

@implementation ApiNameData

+ (instancetype)sharedInstance
{
    static ApiNameData *_sharedInstance = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        _sharedInstance = [[ApiNameData alloc] init];
        
    });
    return _sharedInstance;
}

- (NSMutableDictionary *)apiNameDict
{
    if(!_apiNameDict){
        _apiNameDict = [[NSMutableDictionary alloc] init];
    }
    return _apiNameDict;
}
3.3.2 定义一个刷新的工具类
@interface RefreshUntil : NSObject

+ (RefreshUntil *)shareInstance;

- (void)refreshSuccess:(NSString *)apiName;

- (BOOL)isNeedRefresh:(NSString *)apiName;

- (void)setRefreshTime:(NSNumber *)timestamp withApiName:(NSString *)apiName;

- (void)clear;

@end
#import "RefreshUntil.h"

@implementation RefreshUntil

+ (RefreshUntil *)shareInstance {
    static RefreshUntil *shareInstance = nil;
    static dispatch_once_t predicate;
    dispatch_once(&predicate, ^{
        shareInstance = [[RefreshUntil alloc] init];
    });
    return shareInstance;
}

- (void)refreshSuccess:(NSString *)apiName
{
    [[ApiNameData sharedInstance].apiNameDict setObject:[self nowTimeInterval] forKey:apiName];
}

- (BOOL)isNeedRefresh:(NSString *)apiName
{
    NSNumber *timestamp1 = [self nowTimeInterval];
    NSNumber *timestamp2 = [ApiNameData sharedInstance].apiNameDict[apiName];
   return [timestamp1 doubleValue]<[timestamp2 doubleValue];
}

- (void)setRefreshTime:(NSNumber *)timestamp withApiName:(NSString *)apiName
{
    [[ApiNameData sharedInstance].apiNameDict setObject:timestamp forKey:apiName];
}

- (void)clear
{
    [[ApiNameData sharedInstance].apiNameDict removeAllObjects];
}

//获取当前时间戳
- (NSNumber *)nowTimeInterval
{
    NSDate *date = [NSDate dateWithTimeIntervalSinceNow:0];
    NSString *time = [NSString stringWithFormat:@"%.0f", [date timeIntervalSince1970]];
    NSNumber *timestamp = [NSNumber numberWithDouble:[time doubleValue]];
    return timestamp;
}

@end
3.3.3 每次收到websocket数据更新消息,将全局字典中接口名对应的值更新一次
- (void)receiveRefreshMessage:(NSDictionary *)messageDict
{
    NSString *list_key = messageDict[@"list_key"];
    NSNumber *timestamp = messageDict[@"timestamp"];
    [[RefreshUntil shareInstance] setRefreshTime:timestamp withApiName:list_key];
}
3.3.4 用户进入某个列表页面时,取当前系统的时间和全局字典中这个接口对应的最后刷新时间对比,决定是否需要刷新页面
BOOL isNeedRefresh = [[RefreshUntil shareInstance] isNeedRefresh:@"列表页/关注"];
if(isNeedRefresh==YES){
  [self.tableView.mj_header beginRefreshing];
}
3.3.5 每刷新成功一次列表接口,将全局字典中接口名对应的值更新一次
[[RefreshUntil shareInstance] refreshSuccess:@"列表页/关注"];

3.4 websocket的连接与断开

需要主动连接websocket的情况:

  1. 用户登录成功之后,主动连接websocket;
  2. APP从后台进入前台的时候,主动连接websocket;

需要主动断开websocket的情况:

  1. 用户退出登录之后,主动断开websocket;
  2. APP从前台进入后台的时候,主动断开websocket;

需要重新连接websocket的情况:

  1. websocket自动断开,客户端收不到服务器的心跳包,需要重新连接websocket

效果图
在这里插入图片描述

iOS 自动刷新Demo下载

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/29016.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

基于FPGA MIPS CPU设计学习(1)

关于什么是MIPS以及MIPS架构可参考文章: MIPS架构与指令简介 1 MIPS寄存器学习 MIPS寄存器详细解释如下: • 0 : 即 0: 即 0:

【Shell 脚本速成】04、Shell 脚本格式化输出与用户交互

目录 一、shell格式化输出 1、echo命令 案例演示&#xff1a; 2、输出颜色字体 3、综合案例 二、 用户交互 1、read命令 2、交互输入案例 计算机程序其实就是三步:输入、运算、输出&#xff0c;这个理论也适应于shell编程。 那么计算机是如何将信息按照比较舒服的格式输…

Unity - BRP管线关闭 - UpdateDepthTexture的绘制

最近一直忙着跟项目打杂。。。 比较少时间进修&#xff0c;充电。。。难受香菇 但是 unity 的踩坑经验倒是增加了不少&#xff08;还有很多坑的经验我都懒得写了&#xff0c;但是这些坑浪费查资料时间&#xff0c;还不如自己记下来&#xff0c;便于日后如果还有 BRP 项目的处理…

Neptune CHT-C助力零束打造智舱界王者

9月27日&#xff0c;上汽子品牌飞凡汽车的首款旗舰车型——飞凡R7刚一上市就牢牢吸引了众多视线&#xff0c;在了解了其配置后&#xff0c;用户纷纷称其为“智驾界卷王”。 飞凡R7搭载的RISING MAX 31巨幕&#xff0c;由中国品牌车型最大尺寸的43英寸宽幅真彩三联屏和全球首发量…

CSS的元素显示模式

元素显示模式是什么&#xff1f;&#xff1a; 由于网页中的标签非常多&#xff0c;在不同地方会用到不同类型的标签&#xff0c;了解他们的特点可以更好的布局我们的网页。 元素显示模式就是元素(标签)以什么方式进行显示&#xff0c;比如<div>独占一行&#xff0c;比如…

线索二叉树

目录 一、线索二叉树的类型定义 二、各种线索化的二叉树 三、中序线索二叉树的算法 完整代码&#xff1a; 一、线索二叉树的类型定义 typedef struct BTNode {ElemType data;//数据域struct BTNode* lchild;//左孩子或线索指针struct BTNode* rchild;//右孩子或线索指针int lt…

锐捷MPLS隧道单域实验配置

目录 配置AS100内的IGP路由协议 配置AS内的LDP 配置PE-PE的MP-BGP协议 在PE侧配置PE-CE的路由协议 在CE侧配置PE-CE的路由协议 将CE的路由重发布进MP-BGP中 将MP-BGP的路由重发布进CE中 MPLS隧道——单域基础理论讲解_静下心来敲木鱼的博客-CSDN博客_mpls隧道https://bl…

Python安装

一、官网下载 二、安装 找到下载的安装包&#xff0c;直接双击安装 三、设置环境变量 1、mac自带的python版本 2、修改为新下载的python3.11版本 1&#xff09;修改.bash_profile vi ~/.bash_profile 修改完成后&#xff0c;生效该文件&#xff1a;source ~/.bash_profile…

如何写出公众号爆文?分享你一份爆文写作秘籍

新媒体时代&#xff0c;想要产出一篇公众号爆文真的是难于上青天&#xff01;现在公众号内容同质化严重&#xff0c;如果你没有一些新颖的观点和真本事&#xff0c;是无法从成千上万的公众号中脱颖而出的&#xff01; 如何写出公众号爆文&#xff1f;为什么你看了那么多写作干货…

java--07 面向对象

altenter 文件名和public名保持一致 两个变量指向同一个对象的内存图&#xff1a;如果被一个对象更改 &#xff0c;另外一个对象跟着更改 垃圾回收机制&#xff1a; altenter &#xff1a;添加方法 ctraltt:添加循环 构造器 this关键字 ​​​​​​​ 封装&#x…

周志华机器学习(6):支持向量机

周志华机器学习&#xff08;6&#xff09;&#xff1a;支持向量机6 支持向量机6.1 间隔与支持向量6.2 对偶问题&#xff08;dual problem&#xff09;6.3 核函数6.4 软间隔与正则化基本是大段摘录加上一些自己的补充&#xff0c;去除了冗余的话。6 支持向量机 6.1 间隔与支持向…

实体店应该围绕什么核心来打造自己体系多模式多平台的生态

大家好&#xff0c;我是阿璋&#xff0c;阿璋时不时会发布一些创新的电商资讯&#xff0c;经过电商与疫情的反复摧残&#xff0c;实体商家的收益大不如从前&#xff0c;营业额一跌再跌&#xff0c;迎来实体寒潮&#xff0c;本期给大家分享一个实体店结合共享消费积分联盟广告生…

封神之作,超火Java面试突击手册,进大厂真的就这么简单?

2022年的互联网行业竞争越来越严峻&#xff0c;面试也是越来越难&#xff0c;一直以来我都想整理一套完美的面试宝典&#xff0c;奈何难抽出时间&#xff0c;这套完整的java后端学习路线以及1000道的Java面试手册我整理了整整1个月&#xff0c;上传到Git上目前star数达到了30K …

MCE | 阿尔兹海默症发病机制

阿尔兹海默症 (Alzheimers Disease, AD)&#xff0c;俗语常说的“老年痴呆症”&#xff0c;在奥斯卡提名短片《勿忘我》中以动画形式展现出了阿尔兹海默症患者的世界&#xff0c;动画中的老人&#xff0c;逐渐失去自己的记忆&#xff0c;甚至忘记最爱的人&#xff0c;他的脑海中…

学习软件测试需要注意的几点

⒈ 测试主页技能掌握 关于软件测试&#xff0c;所需要的专业技能&#xff1a; l 基础测试技术&#xff1a;黑盒测试、白盒测试、测试用例设计等; l 软件测试方法&#xff1a;单元测试、功能测试、集成测试、系统测试、性能测试; l 软件测试知识&#xff1a;基础的测试流程管理、…

孩子没有感统失调的表现,还有必要做感统训练吗?

孩子没有感统失调表现&#xff0c;是不是就可以放心了&#xff1f; 孩子训练一段时间&#xff0c;进步非常大&#xff0c;是不是就不需要再继续做训练了&#xff1f; 答案是&#xff1a;无论孩子能力发展如何&#xff0c;感统训练都必不可少。 为什么每个孩子都需要感统训练…

Git——IDEA集成GitHub详细操作

目录 一、 设置GitHub账号 二、分享项目到GitHub 三、push推送本地库到远程库 3.1 第一种方法&#xff1a; 3.2 第二种方法&#xff1a;SSH 四、pull拉取远程库到本地库 五、clone克隆远程库到本地 一、 设置GitHub账号 可以使用下面这个token登录&#xff0c;第一个太慢太慢…

CodeBlocks C++开发环境的配置及使用

CodeBlocks C开发环境的配置及使用 本文引用自作者编写的下述图书; 本文允许以个人学习、教学等目的引用、讲授或转载&#xff0c;但需要注明原作者"海洋饼干叔 叔"&#xff1b;本文不允许以纸质及电子出版为目的进行抄摘或改编。 1.《Python编程基础及应用》&#x…

前端开发性能优化方案-14条

1、减少http请求数量。 单独得一个图片&#xff0c;js,css都是一个请求&#xff0c;将同类合并可以有效得减少请求个数。 2、使用CDN(内容分发网络) 需要新增服务器减少请求得站点个数&#xff08;靠钱解决需要买服务器&#xff09;。 3、添加Expire/Cache-Control头 Expi…

GitHub标星百万的程序员转架构之路,竟被阿里用作内部晋升参考

架构师是很多程序员的奋斗目标&#xff0c;也可以说是职场生涯的一个重要选择方向&#xff0c;今天我就跟大家聊一聊如何从一个程序员成长为一个架构师。 首先我们先来看看架构师的定义到底是什么&#xff1f; 系统架构师是一个不仅需要主持整体又得需体察局部瓶颈并且依据详…