问题原因是有个点差列表的界面,前期是自己socket工具封装自己代码的失误,造成数据源data不断追加,比较专业的行情数据,都会定义规范的结构体,会返回当前数据包的长度,次数在于数据处理时可以处理一部分抛除一部分,但是本人实际项目中只是简单地返回的字符串的data数据,这样就算socket断包,我们也不方便处理,所以就简单地每次只处理接受的数据,(更合理的应该是用nsmutabledata不断的追加拼接数据,然后解包根据包头返回的实际内容的长度截取处理)
然后由于此列表 (交易商数*对应的交易品种)比较多,从而造成数据变化特别频繁,从而造成刷新列表的卡顿
主要修改的几个地方:
1.主推频繁,然后每次主推里边有循环处理数据,所以此处将数据处理放在了子线程中,数据处理好之后用代理或者block返回时拉回主线程
- (void)socket:(GCDAsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag
{
// LOG(@".net行情数据~~~~~");
// if(self.socketData == nil){
// self.socketData = [[NSData alloc] init];
// }
NSString *dataStr = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
if ([dataStr containsString:@"Heart"]) {
// LOG(@"心跳正常");
}else{
// NSString *str = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
// LOG(@"~~~点差数据:%@",str);
self.socketData = [NSData dataWithData:data];
}
//常用方式异步并发+与主线程交互
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
//耗时长的操作
[self dealWithSocketData];//处理数据
[self.socket readDataWithTimeout:10 tag:tag];
});
}
-(void)dealWithSocketData{
if (![_socketData isKindOfClass:[NSData class]]) {
return;
}
if (_socketData.length > 2) {
NSString *dataStr = [[NSString alloc] initWithData:self.socketData encoding:NSUTF8StringEncoding];
NSArray *strArr = [dataStr componentsSeparatedByString:@"#"];
NSMutableArray *strMarry = [NSMutableArray arrayWithArray:strArr];
[strMarry removeLastObject];
NSString *str = strArr[0];
NSString *typeStr = @"";
if (str.length > 2) {
typeStr = [str substringToIndex:2];
}
if (![typeStr isEqualToString:@"01"] && ![typeStr isEqualToString:@"02"]) {
[strMarry removeObjectAtIndex:0];
}
str = strMarry[0];
typeStr = [str substringToIndex:2];
strArr = [NSArray arrayWithArray:strMarry];
if ([typeStr isEqualToString:@"01"]) {
//数据格式 点差 点差类型(01),交易商Code,品名,点差
// 01,000001674566,EURUSD,2.0
NSMutableArray *xlSocketModelMArr = [NSMutableArray arrayWithCapacity:1];
for (NSString *singleStr in strArr) {
if (singleStr.length > 0) {
NSArray *valuesArr = [singleStr componentsSeparatedByString:@","];
NSString *type = valuesArr[0];
if ([type isEqualToString:@"01"]) {
XLSocketModel *model = [XLSocketModel new];
if (valuesArr.count > 2) {
model.n = valuesArr[2];
}
//此处修改逻辑 2017.12.14 只要符合的三个点差
if ([model.n isEqualToString:@"EURUSD"] || [model.n isEqualToString:@"XAUUSD"] || [model.n isEqualToString:@"OILUSD"]) {
if (valuesArr.count > 1) {
model.traderCode = valuesArr[1];
}
if (valuesArr.count > 3) {
model.spread = valuesArr[3];
}
[xlSocketModelMArr addObject:model];
// LOG(@"~~~点差数据:%li~~",xlSocketModelMArr.count);
}else{
continue;
}
}
}
}
dispatch_async(dispatch_get_main_queue(), ^{
//主线程界面刷新
if (self.allTraderSpreadDataBlock) {
self.allTraderSpreadDataBlock(xlSocketModelMArr);
}
if (self.singleTraderCodeSpreadDataBlock) {
self.singleTraderCodeSpreadDataBlock(xlSocketModelMArr);
}
});
}else if ([typeStr isEqualToString:@"02"]){
//数据格式 行情 行情类型(02),交易商Code,品名,买入价,卖出价,点差
// 02,000001674566,EURUSD,2.1345,3.12344,28
NSMutableArray *xlSocketModelMArr = [NSMutableArray arrayWithCapacity:1];
for (NSString *singleStr in strArr) {
if (singleStr.length > 0) {
NSArray *valuesArr = [singleStr componentsSeparatedByString:@","];
NSString *type = valuesArr[0];
if ([type isEqualToString:@"02"]) {
XLSocketModel *model = [XLSocketModel new];
model.traderCode = valuesArr[1];
model.n = valuesArr[2];
model.bid = valuesArr[3];
model.sel = valuesArr[4];
model.spread = valuesArr[5];
[xlSocketModelMArr addObject:model];
}
}
}
dispatch_async(dispatch_get_main_queue(), ^{
//主线程界面刷新
if (self.singleTraderMarketDataBlock) {
self.singleTraderMarketDataBlock(xlSocketModelMArr);
}
});
}
}
}
2.限制刷新频率+只刷新界面上的cell
(1) kPreventRepeatClickTime(0.5);//限制刷新频率,引起卡顿的问题是刷新频率太快,此处硬代码处理
// 防止多次调用
#define kPreventRepeatClickTime(_seconds_) \
static BOOL shouldPrevent; \
if (shouldPrevent) return; \
shouldPrevent = YES; \
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)((_seconds_) * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ \
shouldPrevent = NO; \
}); \
(2)MessageThrottle,限流控制刷新频率,参考https://www.jianshu.com/p/5dacd8778a5a
-(void)reloadTableViewData{
//(1.)限制刷新频率,引起卡顿的问题是刷新频率太快,此处硬代码处理
kPreventRepeatClickTime(0.5);
//(2.)限制刷新的频率 xinle
[self mt_limitSelector:@selector(tableViewReloadData) oncePerDuration:(0.10)];
if (_isAllowRefresh) {
dispatch_async(dispatch_get_main_queue(), ^{
NSArray *cells = [self.tableView indexPathsForVisibleRows];//取出当前界面上的cell
if (cells.count > 0 && self.dataArr.count > 0 && self.dataArr.count >= cells.count) {
//主线程界面刷新
[self.tableView reloadRowsAtIndexPaths:cells withRowAnimation:(UITableViewRowAnimationNone)];
// LOG(@"~~~reloadRowsAtIndexPaths~~~");
}
});
}
}
3.设置开关,当列表拖动的时候不刷新
//开始拖动时禁止刷新
-(void)scrollViewWillBeginDragging:(UIScrollView *)scrollView {
if ([scrollView class] == [self.tableView class]) {
self.isAllowRefresh = 0;
}
}
//减速完毕
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView {
if ([scrollView class] == [self.tableView class]) {
self.isAllowRefresh = 1;
}
}
- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate {
if ([scrollView class] == [self.tableView class]) {
if (!decelerate) {
self.isAllowRefresh = 1;
}
[self getAllTraderSPread];
}
}
tableview刷新可以考虑cell通知监听单刷,不用整个tableview整体刷新