Bootstrap

【iOS】知乎日报第四周总结

【iOS】知乎日报第四周总结

前言

这周笔者主要完成了收藏中心的一个内容和一个对于FMDB这个第三方库的一个学习,以及修改了首页获取三个数据顺序混乱的一个问题,以及优化UITableView的内容。

首页获取三个数据混乱的问题

这里首页获取三个数据混乱的原因主要还是因为网络请求的异步回调的问题,这里笔者上网搜索了一下相关内容后面采用了一个NSConditionLock这个类和一个并行队列来解决,这个类是状态锁,这里笔者还不是很清楚原因,这里可以简单介绍一下状态锁的一个内容:

NSConditionLock 用于控制并发任务的执行顺序

  • NSConditionLock 是一种线程同步机制,它允许线程根据特定条件加锁和解锁。在这段代码中,lock 的初始条件为 0。
  • 每个任务都会调用 lockWhenCondition:i,只有当 lock 的当前条件与 i 相等时,任务才会继续执行,否则会阻塞等待。

该部分内容来自chatgpt

这里笔者给出我下滑加载的部分代码:

-(void)loadData {
    if (self.loading) {
        return;
    }
    self.loading = YES;
    NSInteger num = [self.dateModel.headString intValue];
    NSString* str = [self.dateModel computingTime:self.dateModel.headString andDay:self.iModel.count - 1];
    NSInteger count = self.iModel.count;
    NSLog(@"%@", str);
    self.iView.tableView.tableFooterView = self.iView.footerView;
    [self.iView.activity startAnimating];
    //dispatch_group_t gruop = dispatch_group_create();
    //[self.iView.activity startAnimating];
    NSConditionLock* lock = [[NSConditionLock alloc] initWithCondition:0];
    dispatch_queue_t queue = dispatch_queue_create(@"current", DISPATCH_QUEUE_CONCURRENT);//创建一个并行队列
    for (int i = 0; i < 3; i++) {
        //str = [self.dateModel computingTime:self.dateModel.headString andDay:self.iModel.count - 1];
        //dispatch_group_enter(gruop);
        NSLog(@"执行第%ld个任务", i);
        str = [self.dateModel computingTime:self.dateModel.headString andDay:count - 1 + i];
        NSLog(@"每个任务对应的字符串%@", str);
        [[Manger sharedManger] newDateLoad:^(MainPageModel * _Nonnull model) {
            dispatch_async(queue, ^{
                [lock lockWhenCondition:i];
                [self.iModel addObject:model];
                NSLog(@"%ld", self.iModel.count);
                [lock unlockWithCondition:i + 1];
                if (i == 2) {
                    dispatch_async(dispatch_get_main_queue(), ^{
                        [self.iView.tableView reloadData];
                        [self.iView.activity stopAnimating];
                        self.iView.tableView.tableFooterView = nil;
                        self.loading = NO;
                    });
                }
                NSLog(@"%@", str);
            });
            //dispatch_group_leave(gruop);
        } andNsstring:str];
        //dispatch_group_wait(gruop, DISPATCH_TIME_FOREVER);
    }    
}

FMDB库的一个使用

这里笔者实现收藏中心采用了一个第三方库FMDB这个库来实现的,首先这个库的是用OC来包装sqlite这个小型数据库,然后我们只需要调用她分装好的一个接口就可以了,这里笔者简单介绍一下使用方法,不涉及原理。

创建一个库

创建一个库主要有三种方式来创建,这里笔者介绍的是绝对路径来创建一个数据库。

    1. 绝对路径
    1. 空字符串 @""

会在临时目录创建一个空的数据库,当FMDatabase连接关闭时,数据库文件也被删除。

    1. nil

会创建一个内存中临时数据库,当FMDatabase连接关闭时,数据库会被销毁

在我们对于收藏中心的要求是要存储起来,所以我们采用第一种绝对路径来创建一个数据库

- (void)creatDateBase {
    NSString *path = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES).lastObject;
    self.sqlFilePath = [path stringByAppendingPathComponent:@"collectionCenter.sqlite"];
    self.db = [FMDatabase databaseWithPath:_sqlFilePath];
    //[self delete];
    if ([self.db open]) {
        NSLog(@"load success");
    } else {
        NSLog(@"error");
    }
}

添加数据

对于数据库而言我们永远只用在库的最后添加一个数据就可以了,这里采用的是一个INSERT语句

下面给出相关的一个代码:

-(void)insertData {
    NSString* sqlInsert = @"INSERT INTO  collectionCenter (webPageId, webPageTitle, webImageURL, likes, star) VALUES (?, ?, ?, ?, ?)";
    if ([[DataBaseManger ShareDateBaseManger].db open]) {
        BOOL flag = [[DataBaseManger ShareDateBaseManger].db executeUpdate:sqlInsert, self.webPageId, self.titile, self.imageUrl, @(self.selectLike), @(self.selectStar)];
        if (flag) {
            NSLog(@"success");
        } else {
            NSLog(@"error");
        }
    }
    
}

删除数据

删除数据的语句是DELETE,我们只要知道有一个属性与我们查找的相同就可以进行一个删除的操作。

-(void)deleteData {
    NSString* sqlDelete = @"delete from collectionCenter where (webPageId) = (?) and (webPageTitle) = (?) and (webImageURL) = (?) and (likes) = (?) and (star) = (?)";
    if ([[DataBaseManger ShareDateBaseManger].db open]) {
        BOOL flag = [[DataBaseManger ShareDateBaseManger].db executeUpdate:sqlDelete, self.webPageId, self.titile, self.imageUrl, self.selectLike, self.selectStar];
        if (flag) {
            NSLog(@"删除数据成功");
        } else {
            NSLog(@"删除数据失败");
        }
    } else {
        NSLog(@"打开数据库失败");
    }
}

修改数据

修改数据的语句是一个update其实他和删除语句的大致类似,也是只要有一个属性和我们查找的内容相同就可以了,然后我们修改对应的一个属性值就可以了。

-(void)changeData {
    NSString* sqlDelete = @"update collectionCenter set (star) = (?) where (webPageId) = (?)";
    if ([[DataBaseManger ShareDateBaseManger].db open]) {
        BOOL flag = [[DataBaseManger ShareDateBaseManger].db executeUpdate:sqlDelete, @(self.selectStar), self.webPageId];
        if (flag) {
            NSLog(@"修改数据成功");
        } else {
            NSLog(@"修改数据失败");
        }
    } else {
        NSLog(@"打开数据库失败");
    }
}

以上代码就可以实现一个收藏中心的内容,我们只需要在详情页点击按钮之后进行一个数据内容的一个添加就可以了,添加的web的一个pageId和他的titile来对于数据进行一个判断就可以了,将点过赞和收藏过的页面都进行一个记录,然后下一次点击的时候在数据库中进行一个检索,如果点击过就设置一个对应的button的一个选中。

缓存高度数组

在评论区中因为采用的是一个自适应行高,当数据量太大时候会出现一个问题,就是每一个cell的height都要进行一次重复的运算,导致了很大程度上的一个性能开销,所以我们需要采用一个缓存高度数组的一个手段来解决,我们把加载过的cell高度全部存储在高度数组中,然后下一次使用的时候就到缓存过的高度数组中去获取,这样来减小一个性能上的一个开销。

-(NSMutableArray *)heightAry {
    if (_heightAry == nil) {
        _heightAry = [NSMutableArray array];
        [_heightAry addObject:[NSMutableDictionary dictionary]];
        [_heightAry addObject:[NSMutableDictionary dictionary]];
    }
    return _heightAry;
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
    if (self.heightAry[indexPath.section][@(indexPath.row)] ) {
        NSLog(@"%ld %ld 第几行第几列",indexPath.section, indexPath.row);
        return [self.heightAry[indexPath.section][@(indexPath.row)] doubleValue];
    } else {
        return UITableViewAutomaticDimension;
    }
}
- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath {
    if (!self.heightAry[indexPath.section][@(indexPath.row)] ) {
        NSLog(@"这%ld行没有存储过的一个高度", indexPath.row);
        id height = [NSNumber numberWithDouble:cell.frame.size.height];
        self.heightAry[indexPath.section][@(indexPath.row)] = height;
    } else {
        NSLog(@"这%ld行曾今存储过的一个高度", indexPath.row);
        NSLog(@"%@",  self.heightAry[indexPath.section][@(indexPath.row)]);
        return;
    }
}                                               

小结

大致也算是完成了知乎日报的内容,在学习的过程中出现很多问题,如对于MVC架构的一个职责不是很清楚,对于UITableVIew的函数调用的顺序不是很清楚,对于如何处理网络请求中异步回调的顺序问题,以及一些附加的功能还没有实现,比如说预加载和一个离线加载的内容,笔者会私下抽时间来实现这几个内容。

;