zoukankan      html  css  js  c++  java
  • 绕开Live SDK内存释放bug和实现延迟自动刷新

    之前,上一个版本的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))block
    11 {
    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:self
    5                       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:self
    14                           userState:@"URLPath"];
    15         } else
    16             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:self
    26                   userState:@"URLPath"];
    27     
    28 }
    29     
    30 [_refreshHeaderView refreshLastUpdatedDate];

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

  • 相关阅读:
    78. Subsets
    93. Restore IP Addresses
    71. Simplify Path
    82. Remove Duplicates from Sorted List II
    95. Unique Binary Search Trees II
    96. Unique Binary Search Trees
    312. Burst Balloons
    程序员社交平台
    APP Store开发指南
    iOS框架搭建(MVC,自定义TabBar)--微博搭建为例
  • 原文地址:https://www.cnblogs.com/ipinka/p/2687799.html
Copyright © 2011-2022 走看看