【iOS】知乎日报前三周总结

这几天一直在进行知乎日报的仿写,仿写过程中积累了许多实用的开发经验,并对MVC有了更深的了解,特撰此篇作以总结


目录

    • 第一周
      • 将网络请求封装在一个单例类Manager中
      • SDWebImage库的简单使用
      • 运用时间戳处理当前时间
      • 自定义NavigationBar
    • 第二周
      • 在UITableView的section之间的headerView上画UI
      • WKWebView的使用
      • WKWebView网页加载不出来
      • 线程问题
    • 第三周
      • attempting to add unsupported attribute: (null)错误
      • FMDB数据库的简单使用
      • WebView界面无限右滑
    • 源码


第一周

将网络请求封装在一个单例类Manager中

由于知乎日报所请求的API较多,若将网络请求三板斧直接写在Controller中会代码十分冗杂,干脆直接将AFNetWorking和JSONModel封装到一个全局的Manager单例类中,在Manager类中进行网络请求和数据解析,不同的API写成不同的方法,具体实现看这篇博客()

typedef void(^LatestStoriesBlock)(LatestStoriesModel* latestStoriesModel);
typedef void(^BeforeStoriesModelBlock)(StoriesModel* beforeStoriesModel);
typedef void(^StoriesContentBlock)(StoriesContentModel* storiesContentModel);
typedef void(^StoriesExtraContentBlock)(StoriesExtraContentModel* storiesExtraContentModel);
typedef void(^ErrorBlock)(NSError* error);@interface Manager : NSObject//单例实例
+ (instancetype)sharedManager;//请求最新消息
- (void)requestTopStoriesData: (LatestStoriesBlock)success failure: (ErrorBlock)failure;//缓存网络图片
+ (void)setImage: (id)imageView WithString: (NSString *)string;//请求指定日期的消息内容
- (void)requestBeforeDate: (NSString *)date beforeStoriesData: (BeforeStoriesModelBlock)success failure: (ErrorBlock)failure;//加载Web网页在WebView中
- (void)setWebView: (WKWebView *)webView WithString: (NSString *)string;//请求指定网页的内容(主要为了获取share_url)
- (void)requestWebContentWithID: (NSString *)string StoriesContentData: (StoriesContentBlock)success failure: (ErrorBlock)failure;//请求制定网页的额外内容
- (void)requestExtraContentWithID: (NSString *)string StoriesExtraContentData: (StoriesExtraContentBlock)success failure: (ErrorBlock)failure;@end

解析下来的数据用Block传值(【iOS】属性传值、代理传值(委托)、通知传值、KVO传值、Block传值、单例传值)的方式在Controller中接收

SDWebImage库的简单使用

使用WebImage库主要是为了缓存网络图片并加载在UIImageView上,只需在loadRequest:方法中传入指定的NSURL

+ (void)setImage:(UIImageView *)imageView WithString:(NSString *)string {string = [string stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLQueryAllowedCharacterSet]];NSURL* url = [NSURL URLWithString:string];[imageView sd_setImageWithURL: url placeholderImage: [UIImage imageNamed: @"placeholder.png"]];
}

运用时间戳处理当前时间

时间戳是指格林威治时间1970年01月01日00时00分00秒(北京时间1970年01月01日08时00分00秒)起至现在的总秒数。

处理方法单独写在一个工具类中方便管理

@interface DateModel : NSObject+ (NSTimeInterval)getTimestampWithTimeString: (NSString *)timeString;
+ (NSString *)getMonthWithTimeString: (NSString *)timeString;
+ (NSString *)getDayWithTimeString: (NSString *)timeString;
+ (NSString *)getDateWithTimeString: (NSString *)timeString;
+ (NSString *)getBeforeDateWithTimeString: (NSString *)timeString;@end

获取时间戳方法

//传入时间格式:20230917
+ (NSTimeInterval)getTimestampWithTimeString: (NSString *)timeString {NSDateFormatter* dateFormatter = [[NSDateFormatter alloc] init];[dateFormatter setDateFormat: @"YYYYMMdd"];NSDate* date = [dateFormatter dateFromString: timeString];NSTimeInterval timeStamp = [date timeIntervalSince1970];return timeStamp;
}

通过时间戳处理指定时间

    NSDateFormatter* dateFormatter = [[NSDateFormatter alloc] init];//YYYY获取年份 MM获取月份 dd获取日份 //当然也可以混用,如:@"MM月dd日",这样就会得到一个指定格式的时间字符串[dateFormatter setDateFormat: @"MM"];NSTimeInterval timeStamp = [self getTimestampWithTimeString: timeString];NSDate* date = [NSDate dateWithTimeIntervalSince1970: timeStamp];NSString* string = [dateFormatter stringFromDate: date];

自定义NavigationBar

请添加图片描述

在push页面过程中,使用系统的NavigationBar会发现UI是逐渐消失的,而知乎日报App是第二个页面直接覆盖过去的,想不到什么实现这种效果的巧妙方法,这里我直接在NavigationBar的位置直接粘上一个UIView,并在当前控制器隐藏NavigationBar

- (void)viewWillAppear:(BOOL)animated {[self.navigationController setNavigationBarHidden: YES animated: YES];
}- (void)viewWillDisappear:(BOOL)animated {[self.navigationController setNavigationBarHidden: NO animated: YES];
}

这两个方法涉及UIViewController的生命周期【iOS】ViewController生命周期


第二周

在UITableView的section之间的headerView上画UI

请添加图片描述

tableView提供了这样一个协议方法自定义section

- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section {if (section > 1) {UIView* view = [[UIView alloc] init];UILabel* dateLabel = [[UILabel alloc] init];dateLabel.textColor = [UIColor grayColor];dateLabel.font = [UIFont boldSystemFontOfSize: 15];dateLabel.text = [DateModel getDateWithTimeString: self.beforeDateArray[section - 1]];[view addSubview: dateLabel];UIView* grayView = [[UIView alloc] init];grayView.backgroundColor = [UIColor colorWithRed: 231.0 / 255 green: 231.0 / 255 blue: 231.0 / 255 alpha: 1];[view addSubview: grayView];[dateLabel makeConstraints:^(MASConstraintMaker *make) {make.left.equalTo(view.left).offset(MINIGAP);make.centerY.equalTo(view.centerY);}];[grayView makeConstraints:^(MASConstraintMaker *make) {make.height.equalTo(1);make.left.equalTo(dateLabel.right).offset(MINIGAP);make.right.equalTo(view.right);make.centerY.equalTo(view.centerY);}];return view;} else {return nil;}
}

但section之间的距离跟返回view的高度是没有关系的,要想消除分区之间的留白,给以下属性赋值即可

 self.tableView.sectionHeaderTopPadding = 0;

WKWebView的使用

只需传入NSRequest即可在webView上加载web网页

- (void)setWebView:(WKWebView *)webView WithString:(NSString *)string {//NSLog(@"%@", string);NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString: string]];[webView loadRequest: request];
}

WKWebView网页加载不出来

大概查了一下

出现加载不出来本质原因是,如果没在plist文件中设置App Transport Security Settings的话,加载https链接,肯定是加载不出来的,第一次加载不出来,产生了缓存,第二次再去加载也加载不出来了,可以尝试一下就知道了
请添加图片描述

线程问题

网络请求是在Controller中调用的,请求下来的数据会赋值给View的各种属性,但请求是需要时间的,如果在viewDidLoad里面先初始化view,那么还没等数据请求下来,UI就已经布局,那么只会显示空白的UI控件,未解决这一问题,用到了GCD的一个方法:

        dispatch_async(dispatch_get_main_queue(), ^{[self sendViewStories: latestStoriesModel];[self createTopImages];[self setViewAndModel];[self requestBeforeStoriesWithDate: self.latestStoriesModel.date];});

第三周

请添加图片描述

attempting to add unsupported attribute: (null)错误

使用masonry,设置约束时,约束冲突或约束不全

解决方法就是补充必要的约束或者调整调用顺序

FMDB数据库的简单使用

FMDB库将C语言风格的MySqlite数据库封装成了OC风格的方法,而且操作比C语言文件操作更容易

以点赞集合(存储相应网页的ID)为例,实现了数据库的增删改查:

#pragma mark 点赞操作
- (void)createStoriesLikeSet {NSString* doc = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];NSString* fileName = [doc stringByAppendingPathComponent: @"likeDatabase.sqlite"];NSLog(@"%@", fileName);self.likeDatabase = [FMDatabase databaseWithPath: fileName];if ([self.likeDatabase open]) {BOOL result = [self.likeDatabase executeUpdate: @"CREATE TABLE IF NOT EXISTS likeDatabase (idLabel text NOT NULL)"];if (result) {FMResultSet* resultSet = [self.likeDatabase executeQuery: @"SELECT * FROM likeDatabase"];while([resultSet next]) {[self.storiesLikeSet addObject:[resultSet stringForColumn: @"idLabel"]];}NSLog(@"create table succeed");} else {NSLog(@"fail to open database");}[self.likeDatabase close];}
}- (void)saveStoriesLikeSet {if ([self.likeDatabase open]) {for (NSString* ID in self.storiesLikeSet) {FMResultSet* resultSet = [self.likeDatabase executeQuery: @"SELECT * FROM likeDatabase WHERE idLabel = ?", ID];if (![resultSet next]) {BOOL result = [self.likeDatabase executeUpdate: @"INSERT INTO likeDatabase (idLabel) VALUES (?)", ID];if (result) {NSLog(@"insert table succeed");} else {NSLog(@"insert table error");}}}[self.likeDatabase close];}
}- (void)deleteLikeSetWithID:(NSString*)ID {if ([self.likeDatabase open]) {BOOL result = [self.likeDatabase executeUpdate: @"delete from likeDatabase WHERE idLabel = ?", ID];if (result) {NSLog(@"delete table succeed");} else {NSLog(@"delete table error");}[self.likeDatabase close];}
}

WebView界面无限右滑

向右加载新一天的消息时,主页的tableViewCell也要更新,这里使用了通知中心进行消息传递

    if (self.scrollView.contentOffset.x == Screen_WIDTH * self.numberOfStories) {[[NSNotificationCenter defaultCenter] postNotificationName: @"upDateRight" object: nil];return;}

滑到了新增加的画布时,先通知首页更新一天数据:

//更新首页
[[NSNotificationCenter defaultCenter] addObserver: self selector: @selector(upDateRight) name: @"upDateRight" object: nil];- (void) upDateRight {StoriesModel* storiesModel = [self.beforeStoriesModelArray lastObject];NSString* beforeDate = storiesModel.date;[self requestBeforeStoriesWithDate: beforeDate];
}

然后将更新后的数据传回WebView相关页面,加载新的Web

- (void)requestBeforeStoriesWithDate: (NSString *)date {[self.manager requestBeforeDate: date beforeStoriesData:^(StoriesModel * _Nonnull beforeStoriesModel) {if (!self.beforeStoriesModelArray) {self.beforeStoriesModelArray = [[NSMutableArray alloc] init];}[self.beforeStoriesModelArray addObject: beforeStoriesModel];//NSLog(@"%@", beforeStoriesModel.date);dispatch_async(dispatch_get_main_queue(), ^{[self sendViewStories: beforeStoriesModel];self.mainView.isLoading = NO;[self.mainView.tableView reloadData];NSMutableArray* storiesArray = [[NSMutableArray alloc] init];for (Stories* stories in beforeStoriesModel.stories) {[storiesArray addObject: stories.id];}[[NSNotificationCenter defaultCenter] postNotificationName: @"upDateRight-Two" object:nil userInfo: @{@"value" : storiesArray}];});} failure:^(NSError * _Nonnull error) {NSLog(@"请求过往消息失败");}];
}

但这里面遇到了数组越界问题,向右滑着滑着就访问到了不存在的索引,目前尚未解决
请添加图片描述

源码

Github DEMO

这里先挂一个半成品,之后会想办法解决这个bug,并尝试实现评论区、收藏夹和夜间模式等。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/131481.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

16. 机器学习 - 决策树

Hi,你好。我是茶桁。 在上一节课讲SVM之后,再给大家将一个新的分类模型「决策树」。我们直接开始正题。 决策树 我们从一个例子开始,来看下面这张图: 假设我们的x1 ~ x4是特征,y是最终的决定,打比方说是…

gitlab修改默认nginx端口号

gitlab与nginx部署到同一台机器上,则会导致默认80端口号冲突:所以要修改默认端口号; 第一步:修改/etc/gitlab/gitlab.rb文件:vim /etc/gitlab/gitlab.rb中找到: nginx[listen_port] 8088 (这…

直流无刷电机(BLDC)六步换相驱动

直流无刷电机(BLDC)六步换相驱动 文章目录 直流无刷电机(BLDC)六步换相驱动1. 前言2. 六步换相原理3. 电角度与机械角度4. 动手实践4.1 霍尔输出表测量4.2 换向控制4.3 代码编写 5. 总结 1. 前言 直流无刷电机相对直流有刷电机具…

基于社交网络算法的无人机航迹规划-附代码

基于社交网络算法的无人机航迹规划 文章目录 基于社交网络算法的无人机航迹规划1.社交网络搜索算法2.无人机飞行环境建模3.无人机航迹规划建模4.实验结果4.1地图创建4.2 航迹规划 5.参考文献6.Matlab代码 摘要:本文主要介绍利用社交网络算法来优化无人机航迹规划。 …

【Java 进阶篇】Java Session 原理及快速入门

大家好,欢迎来到本篇博客。今天,我们将探讨Java Web开发中一个重要而令人兴奋的概念,即Session(会话)。Session是一种在Web应用程序中跟踪用户状态和数据的机制。我们将深入了解Session的原理,并通过示例来…

鸿运主动安全云平台任意文件下载漏洞复习

简介 深圳市强鸿电子有限公司鸿运主动安全监控云平台网页存在任意文件下载漏洞,攻击者可通过此漏洞下载网站配置文件等获得登录账号密码 漏洞复现 FOFA语法:body"./open/webApi.html" 获取网站数据库配置文件 POC:/808gps/Mobile…

Mybatis和MybatisPlus使用分页插件

Mybatis分页 安装Pagehelper插件 <dependency><groupId>com.github.pagehelper</groupId><artifactId>pagehelper-spring-boot-starter</artifactId><version>1.4.2</version></dependency>分页查询 public PageBean selectB…

Winform 实现俄罗斯方块游戏(一)

第一步&#xff0c;先用GDI绘制小正方形方块&#xff0c;其它形状的用这个方块合成 如何绘制一个方块&#xff1f;先绘制两个正方形&#xff0c;如下&#xff1a; 然后四周用梯形填充&#xff0c;内部颜色用渐变&#xff0c;这样更有立体感&#xff0c;下篇介绍如何实现。

Observability:使用 OpenTelemetry 手动检测 .NET 应用程序

作者&#xff1a;David Hope 在快节奏的软件开发领域&#xff0c;尤其是在云原生领域&#xff0c;DevOps 和 SRE 团队日益成为应用程序稳定性和增长的重要合作伙伴。 DevOps 工程师不断优化软件交付&#xff0c;而 SRE 团队则充当应用程序可靠性、可扩展性和顶级性能的管理者。…

asp.net docker-compose添加kafka和redis和zookeeper

docker-compose.yml添加 redis:image: redis:alpinekafka:image: "bitnami/kafka:3.1.1"depends_on:- zookeeperzookeeper:image: "bitnami/zookeeper:3.5.10" docker-compose.override.yml添加 redis:ports:- "6379"kafka:links: - zookeepere…

Apache Doris (五十一): Doris数据缓存

🏡 个人主页:IT贫道_大数据OLAP体系技术栈,Apache Doris,Clickhouse 技术-CSDN博客 🚩 私聊博主:加入大数据技术讨论群聊,获取更多大数据资料。 🔔 博主个人B栈地址:豹哥教你大数据的个人空间-豹哥教你大数据个人主页-哔哩哔哩视频 目录 1.

96. 不同的二叉搜索树

给你一个整数 n &#xff0c;求恰由 n 个节点组成且节点值从 1 到 n 互不相同的 二叉搜索树 有多少种&#xff1f;返回满足题意的二叉搜索树的种数。 示例 1&#xff1a; 输入&#xff1a;n 3 输出&#xff1a;5示例 2&#xff1a; 输入&#xff1a;n 1 输出&#xff1a;1提…

PostCSS通过px2rem插件和lib-flexible将px单位转换为rem(root em)单位实现大屏适配

目录 文档postcss中使用postcss-plugin-px2rem安装postcss-plugin-px2rem示例默认配置 webpack中使用postcss-plugin-px2rem项目结构安装依赖文件内容 大屏适配参考文章 文档 类似的插件 postcss-plugin-px2rem https://www.npmjs.com/package/postcss-plugin-px2remhttps://g…

力扣2095.删除链表的中间节点(java快慢指针)

Problem: 2095. 删除链表的中间节点 文章目录 思路解题方法复杂度Code 思路 利用快慢指针&#xff0c;快指针每次走两步&#xff0c;慢指针每次走一步&#xff08;循环退出条件是fast指针不为空同时fast.next不为空&#xff09;&#xff0c;但是我们容易发现这样到最后slow指针…

Docker容器技术实战4

11、docker安全 proc未被隔离&#xff0c;所以在容器内和宿主机上看到的东西是一样的 容器资源控制 cpu资源限制 top命令&#xff0c;查看cpu使用率 ctrlpq防止退出回收&#xff0c;容器会直接调用cgroup&#xff0c;自动创建容器id的目录 cpu优先级设定 测试时只保留一个cpu…

VMware下面的hgfs找不到共享文件夹的解决方法

sudo mount -t fuse.vmhgfs-fuse .host:/ /mnt/hgfs -o allow_other其中 /mnt/hgfs/ 是挂载点&#xff0c;我们也可以修改为其它挂载点 -o allow_other 表示普通用户也能访问共享目录。参考&#xff1a; 主机与VMware虚拟机共享文件夹&#xff1a;解决虚拟机找不到共享文件夹问…

翻页电子杂志制作功略,快收藏,保管好用!

翻页电子杂志&#xff0c;我相信这对大家很熟悉吧&#xff0c;大家也都经常看电子杂志吧。它和我们的生活紧密相关&#xff0c;也极大地改变了我们的阅读方式。听到这“翻页电子杂志”&#xff0c;是不是觉得制作起来肯定很难很复杂&#xff0c;需要专业的人才能制作呢&#xf…

51单片机汇编-点亮一个led

文章目录 前言1.打开IDE2.设置编辑器3.设置输出4. 原理图5.编写代码6 编译7.下载8.其它代码1.LED闪烁2.跑马灯 前言 51单片机基础 本章主要介绍打开一个led,具体采用51汇编 1.打开IDE 选择STC89C52RC 后缀是.asm 2.设置编辑器 3.设置输出 4. 原理图 5.编写代码 ORG 00H;伪代…

「视频编码软件」Media Encoder(Me) 2024 Mac/win中文版下载安装

Adobe Media Encoder(Me) 2024是一款专业的视频编码工具&#xff0c;它可以将各种视频格式进行转换、压缩和编码&#xff0c;以满足不同媒体平台和设备的需求。 以下是 Media Encoder 2023 的主要功能和新增功能&#xff1a; 视频编码和转换&#xff1a;支持将各种视频格式进…

python脚本-网页爬虫获取网页图片

python脚本-网页爬虫获取网页图片 代码 import requests import re import time url"http://10.9.47.154/python-spider/" # 爬取网站的url headers {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like …