博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
绕开Live SDK内存释放bug和实现延迟自动刷新
阅读量:6497 次
发布时间:2019-06-24

本文共 3219 字,大约阅读时间需要 10 分钟。

之前,上一个版本的Live SDK各种内存泄露的bug弄得我比较烦躁,程序闪退崩溃,还要把后台的其他程序的内存都全部占用了。这太不科学了,但是新版本SDK又出现了 一个新问题,就是调用delegate的方法时不检查对象是否已经被dealloc了。我估计它用的是__unsafe_unretained的指针,所以即使对象释放了,指针也不会变为nil。然后就不管3721直接调用该对象的delegate方法,那么程序肯定会马上出错了。但这种错误在上一版SDK上是不会出现的,因为上一版的内存泄露导致controller不会dealloc,同时也不会显现出调用delegate方法出错的问题。

 

一、内存释放bug

那么解决问题的方法,我只能够模仿上一版本的SDK漏洞,就是通过循环引用,避免controller在调用delegate方法之前就被dealloc。

@property (strong, nonatomic) EarthViewController *noDealloc

在调用SDK的API之前,先将noDealloc = self,那么就会因为循环引用,controller无法被dealloc。然后只要在- (void) liveOperationSucceeded:(LiveOperation *)operation通过userState来将noDealloc = nil。那么controller也能够正常释放,再也不会因为用户操作过快而导致奔溃。因为这些controller都用用来浏览文件的,浏览的时候如果用户在刷新但是又没有耐性等,直接就将contrlloer pop了,那么就会出现上面的问题。

 

二、延迟刷新

为了保证能看到更新后SkyDrive上的文件,总是要用户刷新也太不人性化了,所以我加了个自动刷新的功能。一开始我是直接在- (void) viewWillAppear:(BOOL)animated里实现,不过一出现页面就刷新的话,会出现很多问题。例如,在快速不断后退目录的时候,途中经过的目录也会不断刷新,造成最终应该要刷新的目录刷新龟速。同时,这样做也浪费了大量的流量,耗费内存,影响了正在上传和下载任务的速度。

后来我改进了方法,思路就是延迟几秒刷新,不过Objective-C似乎没有,可以延迟执行block的函数。所以先自己实现一个

1 @implementation NSObject (PerformBlockAfterDelay) 2  3  4 - (void)performBlock:(void(^)(void))block afterDelay:(NSTimeInterval)delay 5  6 { 7     [self performSelector:@selector(fireBlockAfterDelay:) withObject:block afterDelay:delay]; 8 } 9 10 - (void)fireBlockAfterDelay:(void(^)(void))block11 {12     13     block();14     15 }16 @end

 

方法很简单,不过很实用。然后就实现刷新的调用

1 [self performBlock:^{2         [UIApplication sharedApplication] setNetworkActivityIndicatorVisible:YES];3         [liveClient getWithPath:[NSString stringWithFormat:@"%@/files?sort_by=name", self.URLPath]4                        delegate:self5                       userState:@"URLPath"];6 }7         afterDelay:3];

不过这样做,还是有问题,实际上所有的controller还是会在3秒后就执行刷新,无论你是否离开了当前这个目录。也就是说,目录无论如何都会刷新,只不过是延迟了3秒。这样实在太糟糕了,虽然也减轻了小部分刷新的压力,但是还是会做无谓的刷新,例如多次后退到同一页面,该页面就进行多次反复刷新。所以要优化一下刷新的思路,保证同一时间不会调用一次以上的刷新,正在刷新的时候也不能重复调用刷新。

于是,我现在的方法是,先定义一个全局变量EarthViewController *currentController,每一次进入到目录时,就先将这个变量赋值为self。那么,这就可以知道当前的controller是哪一个了,当然可以用其他方法实现,方法不唯一。

1 self.title = self.fileTitle; 2 noDeallocURLPath = self; 3 currentController = self; 4  5 //自动刷新 6 if (self.cellsArray) { 7      8     [self performBlock:^{ 9         if (self == currentController && _reloading == NO) {10             [[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:YES];11             _reloading = YES;12             [liveClient getWithPath:[NSString stringWithFormat:@"%@/files?sort_by=name", self.URLPath]13                            delegate:self14                           userState:@"URLPath"];15         } else16             noDeallocURLPath = nil;17     }18             afterDelay:3];19     20 } else {21     22     [[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:YES];23     _reloading = YES;24     [liveClient getWithPath:[NSString stringWithFormat:@"%@/files?sort_by=name", self.URLPath]25                    delegate:self26                   userState:@"URLPath"];27     28 }29     30 [_refreshHeaderView refreshLastUpdatedDate];

由于,现时尚未实现缓存,所以每次进入到新目录就立即进行刷新。至于旧的目录,就继续延迟刷新,_reloading是下拉刷新库的一个变量,负责判断现在是否正在刷新中。同时判断,是否为当前目录,否就不刷新,不浪费资源,因为SDK同时处理请求的能力是有限的。刷新完成后就老规矩,将该还原的变量都全部设回一个正常值。

转载于:https://www.cnblogs.com/ipinka/archive/2012/09/17/2687799.html

你可能感兴趣的文章
uva-12657 - Boxes in a Line(双向链表)
查看>>
python之commands模块
查看>>
android应用开发--------------看RadioGroup源代码,写相似单选选项卡的集成控件(如底部导航,tab等等)...
查看>>
LeetCode - Binary Tree Level Order Traversal
查看>>
FTP协议完全详解
查看>>
iOS:实现图片的无限轮播
查看>>
【C语言天天练(十五)】字符串输入函数fgets、gets和scanf
查看>>
【环境配置】配置sdk
查看>>
accept()
查看>>
USB 2.0 Hub IP Core
查看>>
USB 2.0 OTG IP Core
查看>>
解读浮动闭合最佳方案:clearfix
查看>>
Charles使用
查看>>
Python GUI编程(Tkinter) windows界面开发
查看>>
P(Y|X) 和 P(X,Y)
查看>>
dynamic关键字的使用
查看>>
iOS 音乐播放器之锁屏效果+歌词解析
查看>>
【转】Google 的眼光
查看>>
android O 蓝牙设备默认名称更改
查看>>
阳台的青椒苗
查看>>