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

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

文章目录

前言

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

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

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

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

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

该部分内容来自chatgpt

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

objc 复制代码
-(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连接关闭时,数据库会被销毁

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

objc 复制代码
- (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语句

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

objc 复制代码
-(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,我们只要知道有一个属性与我们查找的相同就可以进行一个删除的操作。

objc 复制代码
-(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其实他和删除语句的大致类似,也是只要有一个属性和我们查找的内容相同就可以了,然后我们修改对应的一个属性值就可以了。

objc 复制代码
-(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高度全部存储在高度数组中,然后下一次使用的时候就到缓存过的高度数组中去获取,这样来减小一个性能上的一个开销。

objc 复制代码
-(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的函数调用的顺序不是很清楚,对于如何处理网络请求中异步回调的顺序问题,以及一些附加的功能还没有实现,比如说预加载和一个离线加载的内容,笔者会私下抽时间来实现这几个内容。

相关推荐
namehu36 分钟前
搞定 iOS App 测试包分发,也就这么简单!😎
前端·ios·app
用户095 小时前
如何避免写垃圾代码:iOS开发篇
ios·swiftui·swift
HarderCoder19 小时前
iOS 知识积累第一弹:从 struct 到 APP 生命周期的全景复盘
ios
叽哥1 天前
Flutter Riverpod上手指南
android·flutter·ios
用户092 天前
SwiftUI Charts 函数绘图完全指南
ios·swiftui·swift
YungFan2 天前
iOS26适配指南之UIColor
ios·swift
权咚3 天前
阿权的开发经验小集
git·ios·xcode
用户093 天前
TipKit与CloudKit同步完全指南
ios·swift
法的空间3 天前
Flutter JsonToDart 支持 JsonSchema
android·flutter·ios
2501_915918413 天前
iOS 上架全流程指南 iOS 应用发布步骤、App Store 上架流程、uni-app 打包上传 ipa 与审核实战经验分享
android·ios·小程序·uni-app·cocoa·iphone·webview