【iOS】知乎日报总结

文章目录

  • 前言
  • 首页
    • 网络请求
    • 轮播图
    • 上滑加载
    • 图片请求
  • 文章详情页
    • WKWebView的使用
    • 点赞、收藏持久化——FMDB的使用
  • 其他问题
    • 沙盒问题
    • 单元格点击
    • 其他
  • 总结

前言

  在系统学习了OC语言和UI控件后,知乎日报是第一个比较大的项目,耗时一个多月时间,里面使用到了YYModel、Masonry、AFNetworking、FMDB等多个第三方库。项目总体采用MVC大框架,下面是对这段时间知乎日报项目的总结。

首页

  首页主要是由一个轮播图和一个TableViewCell构成的,其中都要通过知乎日报的API对顶部轮播图和下面的实时文章进行网络请求。
在这里插入图片描述

网络请求

  在这里进行网络请求时,笔者将所有的网络请求封装到了一个manager类里,在需要时可直接通过manager单例进行方法调用。这里可以参考【iOS】使用AFNetworking进行网络请求
【iOS】使用一个单例通过AFNetworking来实现网络请求
该项目中使用到的开源API可参考:知乎日报 API 分析(如何规范api设计)

这里以对顶部的文章进行网络请求为例:

//Manager.h
+ (instancetype)sharedManager;- (void)requestTopStoriesData: (LatestStoriesBlock)success failure: (ErrorBlock)failure;//Manager.m
static id manager = nil;+ (instancetype)sharedManager {if (!manager) {static dispatch_once_t onceToken;dispatch_once(&onceToken, ^{manager = [[Manager alloc] init];});}return manager;
}- (void)requestTopStoriesData:(LatestStoriesBlock)success failure:(ErrorBlock)failure {[[AFHTTPSessionManager manager] GET:@"https://news-at.zhihu.com/api/4/news/latest" parameters: nil progress: nil success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {LatestStoriesModel* latestStoriesModel = [[LatestStoriesModel alloc] initWithDictionary: responseObject error: nil];success(latestStoriesModel);} failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {failure(error);}];
}

对当天推送内容和过往内容的申请类似,就不多赘述了。

轮播图

至于顶部的轮播图,跟之前ZARA和网易云仿写项目的轮播图有异曲同工之妙。

//MainViewController.h
@property (nonatomic, strong)NSMutableArray* imageViewArray;
@property (nonatomic, strong)NSMutableArray* titleArray;
@property (nonatomic, strong)NSMutableArray* userNameArray;//MainViewController.m
- (void) topStroies {self.imageViewArray = [[NSMutableArray alloc] init];self.titleArray = [[NSMutableArray alloc] init];self.userNameArray = [[NSMutableArray alloc] init];UIImageView* firstImageView = [[UIImageView alloc] init];Top_Stories* top_stories = self.latestStoriesModel.top_stories[4];[Manager setImage: firstImageView WithString: top_stories.image];[self.imageViewArray addObject: firstImageView];for (Top_Stories* top_stories in self.latestStoriesModel.top_stories) {UIImageView* imageView = [[UIImageView alloc] init];[Manager setImage: imageView WithString: top_stories.image];[self.imageViewArray addObject: imageView];[self.titleArray addObject: top_stories.title];[self.userNameArray addObject: top_stories.hint];}UIImageView* lastImageView = [[UIImageView alloc] init];top_stories = self.latestStoriesModel.top_stories[0];[Manager setImage: lastImageView WithString: top_stories.image];[self.imageViewArray addObject: lastImageView];self.mainView.imageViewArray = self.imageViewArray;self.mainView.titleArray = self.titleArray;self.mainView.userNameArray = self.userNameArray;
}

上滑加载

对于过往文章的上滑加载,我们只需要进行通知传值,然后请求数据后更新主页面的tableView即可。

- (void)viewDidLoad {[[NSNotificationCenter defaultCenter] addObserver: self selector: @selector(loadBeforeStories) name: @"requestBeforeStories" object: nil];
}- (void)requestBeforeStories {StoriesModel* storiesModel = [self.beforeStoriesModelArray lastObject];NSString* before1Date = storiesModel.date;[self.manager requestBeforeDate: before1Date beforeStoriesData:^(StoriesModel * _Nonnull beforeStoriesModel) {[self.beforeStoriesModelArray addObject: beforeStoriesModel];[self sendViewStories: beforeStoriesModel];NSString* before2Date = [DateModel getBeforeDateWithTimeString: beforeDate];[self.manager requestBeforeDate: before2Date beforeStoriesData:^(StoriesModel * _Nonnull beforeStoriesModel) {[self.beforeStoriesModelArray addObject: beforeStoriesModel];[self sendViewStories: beforeStoriesModel];NSString* before3ForeDate = [DateModel getBeforeDateWithTimeString: foreForeDate];[self.manager requestBeforeDate: before3Date beforeStoriesData:^(StoriesModel * _Nonnull beforeStoriesModel) {[self.beforeStoriesModelArray addObject: beforeStoriesModel];[self sendViewStories: beforeStoriesModel];dispatch_async(dispatch_get_main_queue(), ^{self.mainView.isLoading = NO;[self.mainView.tableView reloadData];});} failure:^(NSError * _Nonnull error) {NSLog(@"请求前三天消息失败");}];} failure:^(NSError * _Nonnull error) {NSLog(@"请求前两天消息失败");}];} failure:^(NSError * _Nonnull error) {NSLog(@"请求前一天消息失败");}];
}

主页面这里在程序运行加载view时可能会出现view空白的情况,查询资料了解到可能是线程的问题,我们是在Controller中调用的网络请求,请求下来的数据会赋值给View的各种属性,然后UI就会将这些数据展现出来,但请求是需要时间的,而UI的布局会比网络请求快,所以如果在viewDidLoad里面先初始化view,那么数据还没请求下来,UI就已经布局,导致我们的View里的UI控件是空白的,为解决这一问题,这里需要用到GCD的一个方法:

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

dispatch_async(dispatch_get_main_queue(), ^{ … }):这个函数调用将一个代码块提交到主队列(主线程)上异步执行。这通常用于确保UI更新和其他需要在主线程执行的操作能够正确运行,特别是在从后台线程返回结果时。

这里笔者对GCD的学习还较为浅显,只是能用于解决UI更新冲突的问题,至于具体的原理和GCD更多的使用方法,笔者后期还会再进行学习。

图片请求

在对图片进行网络请求时,请求到的图片内容都是url,此时我们没法直接将其转化为图片形式,所以就要使用一个第三方库——SDWebImage库,这个库可以将我们请求到的url转为图片,其用法如下:
首先,我们在podfile文件中导入该库,然后使用终端命令导入项目,跟之前Masonry库的导入步骤一样,然后在我们需要获取图片的文件里导入SDWebImage的头文件,之后获取我们通过网络请求到的图片的url,使用 SDWebImage 中的 sd_setImageWithURL: 方法将网络图片加载到 UIImageView 中。

NSString *string = [string stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLQueryAllowedCharacterSet]];NSURL* url = [NSURL URLWithString:string];[self.imageView sd_setImageWithURL: url placeholderImage: [UIImage imageNamed: @"placeholder.png"]];

文章详情页

  在文章详情页主要实现一个文章内容的布局,文章底部工具栏的设置和文章的点赞、收藏功能及其的持久化,还有文章评论区页面的展开。
在这里插入图片描述

WKWebView的使用

WKWebView 是苹果在 iOS 8 及以后版本中引入的一个用于加载和显示网页内容的类,它是 WebKit 框架的一部分,用于替代旧的 UIWebView。WKWebView 提供了更好的性能、更强的功能和更高的安全性。
要在iOS应用中使用 WKWebView,需要导入 WebKit 框架,并创建 WKWebView 的实例。

#import <WebKit/WebKit.h>// 创建一个 WKWebView 实例
WKWebView *webView = [[WKWebView alloc] initWithFrame:self.view.frame];// 加载一个网页
NSURL *url = [NSURL URLWithString:@"https://www.example.com"];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
[webView loadRequest:request];

在编写文章详情页时,刚开始会出现UI加载空白即WKWebView网页加载不出来的情况,查询资料并检查代码之后,发现是App Transport Security Settings(ATS)设置问题:
如果没有在 Info.plist 文件中设置 App Transport Security Settings,加载 https 链接可能会失败。需要在 Info.plist 中添加 NSAppTransportSecurity 字典,并将 NSAllowsArbitraryLoads 设置为 YES 以允许连接到任何域。

在这里插入图片描述

App Transport Security (ATS) 是苹果公司在其移动操作系统 iOS 9 和 OS X 10.11 El Capitan 及更高版本中引入的一项安全特性。ATS 的目的是提高应用程序的网络安全性,确保所有的网络通信都通过安全的方式进行。
强制使用 HTTPS:
ATS 要求应用程序的所有网络请求都必须通过 HTTPS 发送,以保护用户数据免受中间人攻击和窃听。
数据加密:
ATS 强制使用强加密标准,包括 TLS 1.2 或更高版本,并要求使用前向保密(Forward Secrecy)和强加密套件。
限制明文请求:
ATS 限制了对明文 HTTP、FTP 或非加密的 WebSocket 连接的请求,以防止敏感信息在传输过程中被截获。
允许自定义:
开发者可以在 Info.plist 文件中配置 ATS 设置,以适应特定的网络通信需求,例如允许特定的非安全连接或为特定域名设置例外。
内容安全策略:
ATS 鼓励开发者使用内容安全策略(CSP)来减少跨站脚本(XSS)攻击的风险。
网络代理:
ATS 支持网络代理的使用,允许应用程序通过代理服务器进行网络通信。
应用审核:
苹果在应用审核过程中会检查 ATS 的合规性,如果开发者需要为应用启用非安全的网络连接,需要在应用审核时提供充分的理由。
隐私保护:
ATS 有助于保护用户的隐私,因为它限制了第三方跟踪用户网络行为的能力。
逐步淘汰:
从 iOS 11 和 macOS 10.13 High Sierra 开始,苹果鼓励开发者使用更现代的网络技术,如 WKWebView,这些技术默认启用 ATS 并提供更好的性能和安全性。

点赞、收藏持久化——FMDB的使用

使用FMDB库之前,先通过 Cocoapods 引入到项目中,使用 pod ‘FMDB’ 命令进行安装。
关于FMDB的具体用法见:【iOS】iOS的轻量级数据库——FMDB

这里以对收藏功能实现持久化为例:

- (void)createStoriesCollect {NSString* doc = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];NSString* filename = [doc stringByAppendingPathComponent: @"collectDatabase.sqlite"];self.collectDatabase = [FMDatabase databaseWithPath: filename];if ([self.collectDatabase open]) {BOOL result = [self.collectDatabase executeUpdate: @"CREATE TABLE IF NOT EXISTS collectDatabase (idLabel text NOT NULL)"];if (result) {FMResultSet* resultSet = [self.collectDatabase executeQuery: @"SELECT * FROM collectDatabase"];while ([resultSet next]) {[self.storiesCollect addObject: [resultSet stringForColumn: @"idLabel"]];}NSLog(@"create succeed");} else {NSLog(@"create error");}[self.collectDatabase close];}
}- (void)saveStoriesCollect {if ([self.collectDatabase open]) {for (NSString* ID in self.storiesCollectSet) {FMResultSet* resultSet = [self.collectDatabase executeQuery: @"SELECT * FROM collectDatabase WHERE idLabel = ?", ID];if (![resultSet next]) {BOOL result = [self.collectDatabase executeUpdate: @"INSERT INTO collectDatabase (idLabel) VALUES (?)", ID];if (result) {NSLog(@"insert succeed");} else {NSLog(@"insert error");}}}[self.collectDatabase close];}
}- (void)deleteCollectWithID:(NSString*)ID {if ([self.collectDatabase open]) {BOOL result = [self.collectDatabase executeUpdate: @"delete from collectDatabase WHERE idLabel = ?", ID];if (result) {NSLog(@"delete succeed");} else {NSLog(@"delete error");}}
}

其他问题

沙盒问题

刚开始写的时候运行项目会Failed,然后出现这样的报错:Sandbox: rsync.samba(27013) deny(1) file-write-create /Users /…

查询完资料说是:

在 iOS 项目中,特别是在使用 Xcode 时,沙盒环境阻止了应用写入不被允许的文件或目录。

解决方法:在 Xcode 中,在项目的 Build Settings 中搜索 User Script Sandboxing 并将其值设置为 NO 。
在这里插入图片描述

单元格点击

单元格点击后自动取消选中需要使用deselectRowAtIndexPath: animated:方法。

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {if (indexPath.row == 1) {[[NSNotificationCenter defaultCenter] postNotificationName: @"didselectCollection" object: nil userInfo: nil];}[tableView deselectRowAtIndexPath:indexPath animated:YES];
}

其他

xcode SDK does not contain ‘libarclite‘问题解决方法:
在这里插入图片描述
Framework ‘Pods_______’ not found问题解决参考:
framework not found Pods_xxx xcode打包错误解决方法

Linker command failed with exit code 1 (use -v to see invocation)问题解决参考:
Xcode出现( linker command failed with exit code 1)错误总结

总结

  知乎日报是第一个比较大的项目,耗时一个多月时间,在完成过程中遇到了很多问题,也学到了很多,比如YYModel、AFNetworking、SDWebImage、FMDB等的用法,后续还会继续学习GCD等关于iOS项目线程的问题。

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

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

相关文章

NLP信息抽取大总结:三大任务(带Prompt模板)

信息抽取大总结 1.NLP的信息抽取的本质&#xff1f;2.信息抽取三大任务&#xff1f;3.开放域VS限定域4.信息抽取三大范式&#xff1f;范式一&#xff1a;基于自定义规则抽取&#xff08;2018年前&#xff09;范式二&#xff1a;基于Bert下游任务建模抽取&#xff08;2018年后&a…

【Linux】网络连接模式,VM:桥接、NAT、仅主机如何选择?

1、网络类型 虚拟机建立时的常见网络类型有3种&#xff1a;桥接、NAT&#xff08;Network Address Translation&#xff0c;网络地址转换&#xff09;、仅主机&#xff08;Host Only&#xff09; 桥接&#xff1a;VM直接连接路由器&#xff0c;与物理机地位相同&#xff1b;N…

Spring Boot 3启动加载器详解(含源码解析)

一、引言 Spring Boot 3启动加载器是提升开发效率和应用程序启动速度的关键组件。本文将详细介绍Spring Boot 3的启动加载器&#xff0c;包括其实现方式、应用场景及工作原理等。 说明&#xff1a;本文分析使用的Spring Boot源码版本为3.3.5 二、启动加载器简介 启动加载器…

UDP客户端服务器通信

在这篇博客中&#xff0c;我们将探索 UDP&#xff08;用户数据报协议&#xff09; 通信&#xff0c;简要地说&#xff0c;UDP 是一种无连接、快速但不可靠的通信协议&#xff0c;适用于需要快速数据传输但对丢包容忍的场景&#xff0c;比如视频流和在线游戏。就像《我是如此相信…

手机实时提取SIM卡打电话的信令声音-智能拨号器的双SIM卡切换方案

手机实时提取SIM卡打电话的信令声音 --智能拨号器app的双SIM卡切换方案 一、前言 在蓝牙电话的方案中&#xff0c;由于采用市场上的存量手机来做为通讯呼叫的载体&#xff0c;而现在市面上大部分的手机都是“双卡双待单通”手机&#xff0c;简称双卡双待手机。即在手机开机后…

Spring Boot 同时接受文件和实体及 Postman 测试实战

Spring Boot 文件上传及 Postman 测试指南 在本文中&#xff0c;我们将介绍如何使用 Spring Boot 上传文件并通过 Postman 测试接口。我们会基于以下接口作为示例&#xff1a; Boolean importDevicePushConfig(RequestParam("file") MultipartFile file,DevicePush…

Paddle Inference部署推理(一)

一&#xff1a;Paddle Inference推理 简介 Paddle Inference 是飞桨的原生推理库&#xff0c;提供服务器端的高性能推理能力。由于 Paddle Inference 能力直接基于飞桨的训练算子&#xff0c;因此它支持飞桨训练出的所有模型的推理。 Paddle Inference 功能特性丰富&#xff…

搭建文件服务器并使用Qt实现文件上传和下载(带账号和密码)

文章目录 0 背景1 搭建文件服务器2 代码实现文件上传和下载2.1 在pro文件中添加网络支持2.2 创建网络管理类2.3 文件上传2.4 文件下载 3 扩展&#xff08;其他方法实现文件上传和下载&#xff09;3.1 python3.2 npm3.3 ftp服务器 4 完整的代码 0 背景 因为需要使程序具备在远程…

社交新零售模式下“2+1 链动模式 S2B2C 商城小程序”的创新实践与发展策略

摘要&#xff1a;随着实体商业与社交网络深度融合&#xff0c;社交新零售蓬勃兴起&#xff0c;“21 链动模式 S2B2C 商城小程序”作为其中创新典范&#xff0c;融合独特激励机制与数字化运营优势&#xff0c;重塑零售生态。本文剖析该模式架构、运作逻辑&#xff0c;探讨其在私…

【Git】Git 完全指南:从入门到精通

Git 完全指南&#xff1a;从入门到精通 Git 是现代软件开发中最重要的版本控制工具之一&#xff0c;它帮助开发者高效地管理项目&#xff0c;支持分布式协作和版本控制。无论是个人项目还是团队开发&#xff0c;Git 都能提供强大的功能来跟踪、管理代码变更&#xff0c;并保障…

华为E9000刀箱(HWE9000V2)服务器硬件监控指标解读

随着数据中心规模的不断扩大&#xff0c;服务器的稳定性和可靠性变得尤为重要。华为E9000刀箱&#xff08;HWE9000V2&#xff09;作为一款高性能的服务器设备&#xff0c;其硬件状态的实时监控对于保障业务的连续性和系统的稳定运行至关重要。 监控易作为一款专业的IT基础设施监…

Css—实现3D导航栏

一、背景 最近在其他的网页中看到了一个很有趣的3d效果&#xff0c;这个效果就是使用css3中的3D转换实现的&#xff0c;所以今天的内容就是3D的导航栏效果。那么话不多说&#xff0c;直接开始主要内容的讲解。 二、效果展示 三、思路解析 1、首先我们需要将这个导航使用一个大…

gitee:删除仓库

1、点击主页面设置 2、找到左侧导航栏-数据管理->仓库空间信息&#xff1b;找到需要删除的仓库->点击设置 3、点击左侧仓库设置->点击右侧删除仓库 4、输入提示内容->确认删除 5、输入密码验证 6、成功删除提示

探索 Python 任务自动化的新境界:Invoke 库揭秘

文章目录 探索 Python 任务自动化的新境界&#xff1a;Invoke 库揭秘背景&#xff1a;为何选择 Invoke&#xff1f;什么是 Invoke&#xff1f;如何安装 Invoke&#xff1f;5个简单的库函数使用方法1. 定义任务2. 带参数的任务3. 运行 Shell 命令4. 任务参数化5. 列出任务 场景应…

深入理解计算机系统,源码到可执行文件翻译过程:预处理、编译,汇编和链接

1.前言 从一个高级语言到可执行程序&#xff0c;要经过预处理、编译&#xff0c;汇编和链接四个过程。大家可以思考下&#xff0c;为什么要有这样的过程&#xff1f; 我们学习计算机之处&#xff0c;就应该了解到&#xff0c;计算机能够识别的只有二进制语言&#xff08;这是…

六通道串口服务器

型号&#xff1a;SG-TCP232-620 1.1 功能 1.1.1 基本功能 串口服务器是串口 RS232/422/485 和以太网之间的一个转换器&#xff0c;实现串口数 据和以太网数据的双向透明传输&#xff0c;可以让串口设备立即联网&#xff0c;典型应用拓扑如下&#xff1a; 1.1.2 特色功能…

Ubuntu 18.04 中安装 RDKit(针对 Python 2.7)

✅作者简介&#xff1a;2022年博客新星 第八。热爱国学的Java后端开发者&#xff0c;修心和技术同步精进。 &#x1f34e;个人主页&#xff1a;Java Fans的博客 &#x1f34a;个人信条&#xff1a;不迁怒&#xff0c;不贰过。小知识&#xff0c;大智慧。 &#x1f49e;当前专栏…

websocket前后端长连接之java部分

一共有4个类,第一个WebSocketConfig 配置类 Configuration EnableWebSocket public class WebSocketConfig implements WebSocketConfigurer {Autowiredprivate WebSocketHandler webSocketHandler;Autowiredprivate WebSocketInterceptor webSocketInterceptor;Overridepubli…

PyCharm中Python项目打包并运行到服务器的简明指南

目录 一、准备工作 二、创建并设置Python项目 创建新项目 配置项目依赖 安装PyInstaller 三、打包项目 打包为可执行文件 另一种打包方式&#xff08;使用setup.py&#xff09; 四、配置服务器环境 五、上传可执行文件到服务器 六、在服务器上运行项目 配置SSH解释…

【UE5 C++课程系列笔记】05——组件和碰撞

效果 可以看到我们可以实现的功能是 &#xff08;1&#xff09;可以通过鼠标旋转视角 &#xff08;2&#xff09;通过使用Pawn移动组件来控制Pawn移动 &#xff08;3&#xff09;Pawn碰到物体会被阻挡然后逐渐滑动 &#xff08;4&#xff09;通过空格切换激活/关闭粒子效果…