一些MJRefresh的坑

1.MJRefresh(主要封裝了六種刷新控件)

MJ 框架圖
作用
MJRefreshComponent 繼承自UIView,最基本的刷新類
MJRefreshHeader 最基本的下拉刷新類
MJRefreshStateHeader 可以下拉刷新,但是只有文字
MJRefreshNormalHeader 默認的刷新樣式,有文字,有上下箭頭,有菊花

主要使用以下幾個

  • MJRefreshNormalHeader
  • MJRefreshGifHeader
  • MJRefreshBackNormalFooter
  • MJRefreshBackGifFooter
  • MJRefreshAutoNormalFooter
  • MJRefreshAutoGIfFooter

2.MJ 刷新block造成veiwcontroller內(nèi)存不釋放問題

? self的成員變量Tableview.mj_header 引用了刷新方法的block,block引用了self的函數(shù),同時還引用了成員變量Tableview.mj_header ,造成了兩個循環(huán)引用,導致了viewcontroller不釋放。

  • 以下是引起循環(huán)引用的代碼:
_tableV1.mj_header = [MJRefreshNormalHeader headerWithRefreshingBlock:^{
    [_tableV1.mj_header beginRefreshing];
    //request
    [self removeAllTableAry];
    [self refreshRequest];
    [_tableV1.mj_header endRefreshing];
}];
  • 而當使用target方法時并不會產(chǎn)生循環(huán)引用這個問題。
_tableV1.mj_header = [MJRefreshNormalHeader headerWithRefreshingTarget:self refreshingAction:@selector(refreshRequest)];

_tableV1.mj_footer = [MJRefreshBackNormalFooter footerWithRefreshingTarget:self refreshingAction:@selector(loadTableV1MoreData)];   
  • 打破MJ方法中的block循環(huán)引用如下:
__weak typeof(self) weakSelf = self;
__weak typeof(_tableV1.mj_header) weakHeader = _tableV1.mj_header;
_tableV1.mj_header = [MJRefreshNormalHeader headerWithRefreshingBlock:^{
    typeof (weakSelf)strongSelf = weakSelf;
    typeof (weakHeader)strongHeader = weakHeader;
    [strongHeader beginRefreshing];
    //request
    [strongSelf refreshRequest];
    [strongHeader endRefreshing];
}];

3.討論下關于block循環(huán)引用的問題

//情況一:

- (void)case1 {

? NSLog(@"case 1 Click");

? dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.3 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{

? self.name = @"case 1";

? });

? }

//情況二

- (void)case2 {

? NSLog(@"case 2 Click");

? __weak typeof(self) weakSelf = self;

? [self.teacher requestData:^(NSData *data) {

? typeof(weakSelf) strongSelf = weakSelf;

? strongSelf.name = @"case 2";

? }];

? }

//情況三

? - (void)case3 {

? NSLog(@"case 3 Click");

? [self.teacher requestData:^(NSData *data) {

? self.name = @"case 3";

? }];

? }

//情況四

? - (void)case4 {

? NSLog(@"case 4 Click");

? [self.teacher requestData:^(NSData *data) {

? self.name = @"case 4";

? self.teacher = nil;

? }];

? }

//情況五

? - (void)case5 {

? NSLog(@"case 5 Click");

? Teacher *t = [[Teacher alloc] init];

? [t requestData:^(NSData *data) {

? self.name = @"case 5";

? }];

? }

//情況六

? - (void)case6 {

? NSLog(@"case 6 Click");

? [self.teacher callCase6BlackEvent];

? self.teacher.case6Block = ^(NSData *data) {

? self.name = @"case 6";

? //下面兩句代碼任選其一

? self.teacher = nil;

? // self.teacher.case6Block = nil;

? };

? }

分析

  • 情況一:執(zhí)行了dealloc,不泄露,此情況雖然是block,但未形成保留環(huán)block -> self
  • 情況二:執(zhí)行了dealloc,不泄露,此情況就是內(nèi)存泄漏后的一般處理了 self ->teacher ->block ->strongSelf,后面那個strongSelf和原來的self并沒有直接關系,因為strongSelf是通過weakSelf得來的,而weakSelf又沒有強引用原來的self
  • 情況三:未執(zhí)行dealloc,內(nèi)存泄漏,此情況就是最典型的循環(huán)引用了,形成保留環(huán)無法釋放,self ->teacher ->block ->self
  • 情況四:執(zhí)行了dealloc,不泄露,雖然也是保留環(huán),但通過最后一句,使self不再強引用teacher,打破了保留環(huán)
  • 情況五:執(zhí)行了dealloc,不泄露,未形成保留環(huán) t ->block ->self
  • 情況六:執(zhí)行了dealloc,不泄露,最后兩句代碼任選其一即可防止內(nèi)存泄漏,self.teacher 或者 case6Block 置為空都可以打破 retain cycle

PS: 雖然情況四、情況六的寫法都可以防止內(nèi)存泄漏,不過為了統(tǒng)一,個人建議最好還是按照普通寫法即情況二的寫法。

最后編輯于
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容