【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.mzph.cn/pingmian/62289.shtml

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

相关文章

网安瞭望台第6期 :XMLRPC npm 库被恶意篡改、API与SDK的区别

国内外要闻 XMLRPC npm 库被恶意篡改&#xff0c;窃取数据并部署加密货币挖矿程序 网络安全研究人员发现了一起在 npm 包注册表上活跃了一年多的软件供应链攻击。名为 0xengine/xmlrpc 的 npm 包最初是一个无害的库&#xff0c;基于 JavaScript&#xff0c;用于 Node.js 的 XML…

双向链表

目录 链表的分类 概念 双向链表的实现 ① 结构 ② 初始化 ③ 打印 ④ 插入数据 ⑤ 删除数据 ⑥ 查找数据 ⑦ 在pos位置之前插入数据 ⑧ 删除pos位置的数据 ⑨ 销毁链表 总结 链表的分类 虽然有这么多的链表的结构&#xff0c;但是我们实际中最常⽤还是两种结构&…

怎么样才算得上熟悉高并发编程?

提到并发编程很多人就会头疼了&#xff1b;首先就是一些基础概念&#xff1a;并发&#xff0c;并行&#xff0c;同步&#xff0c;异步&#xff0c;临界区&#xff0c;阻塞&#xff0c;非阻塞还有各种锁全都砸你脸上&#xff0c;随之而来的就是要保证程序运行时关键数据在多线程…

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

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

clickhouse 分片键的重要性

文章目录 背景反思为啥出现问题为啥默认的语义是local 背景 问题背景 详细内容可以看这个 反思为啥出现问题 为啥会出现链接里出现的问题&#xff0c;对于goal join 和 join 语义不一样的问题&#xff0c;那是因为分片键设计不合理的情况 如果表a和表b 都是user_id 作分片键…

S4 UPA of AA :新资产会计概览

通用并行会计&#xff08;Universal Parallel Accounting&#xff09;可以支持每个独立的分类账与其他模块集成&#xff0c;UPA主要是为了支持平行评估、多货币类型、财务合并、多准则财务报告的复杂业务需求 在ML层面UPA允许根据不同的分类账规则对物料进行评估&#xff0c;并…

数据结构之堆:原理与实现

1. 什么是堆&#xff1f; 堆&#xff08;Heap&#xff09;是一种特殊的完全二叉树&#xff0c;它的每个节点都遵循以下性质之一&#xff1a; 最大堆&#xff08;Max-Heap&#xff09;&#xff1a;每个节点的值都大于等于其子节点的值&#xff0c;根节点是最大值。最小堆&…

DreamCamera2相机预览变形的处理

最近遇到一个问题&#xff0c;相机更换了摄像头后&#xff0c;发现人像角度顺时针旋转了90度&#xff0c;待人像角度正常后&#xff0c;发现 预览时图像有挤压变形&#xff0c;最终解决。在此记录 一人像角度的修改 先放示意图 设备预览人像角度如图1所示&#xff0c;顺时针旋…

GPT相关的学术库——收藏更新自用

GOT-OCR2.0 General OCR Theory: Towards OCR-2.0 via a Unified End-to-end Model https://github.com/Ucas-HaoranWei/GOT-OCR2.0/tree/main ChatPaper 工具名称工具作用是否在线&#xff1f;在线预览备注ChatPaper通过ChatGPT实现对论文进行总结&#xff0c;帮助科研人进…

LLM之学习笔记(一)

前言 记录一下自己的学习历程&#xff0c;也怕自己忘掉了某些知识点 Prefix LM 和 Causal LM区别是什么&#xff1f; Prefix LM &#xff08;前缀语⾔模型&#xff09;和 Causal LM&#xff08;因果语言模型&#xff09;是两者不同类型的语言模型&#xff0c;它们的区别在于生…

Python语法基础(三)

&#x1f308;个人主页&#xff1a;羽晨同学 &#x1f4ab;个人格言:“成为自己未来的主人~” 我们这篇文章来说一下函数的返回值和匿名函数 函数的返回值 我们先来看下面的这一段函数的定义代码 # 1、返回值的意义 def func1():print(111111111------start)num166print…

用Pycharm安装manim

由于版本和工具的差异&#xff0c;manim的安装方式不尽相同。本文用Pycharm来安装manim. 一、准备工作&#xff1a;安装相应版本的python、pycharm和ffmpeg. 此处提供一种安装ffmpeg的方式 下载地址&#xff1a;FFmpeg 下载后&#xff0c;解压到指定目录。 配置环境变量&am…

【线程】Java多线程代码案例(2)

【线程】Java多线程代码案例&#xff08;2&#xff09; 一、定时器的实现1.1Java标准库定时器1.2 定时器的实现 二、线程池的实现2.1 线程池2.2 Java标准库中的线程池2.3 线程池的实现 一、定时器的实现 1.1Java标准库定时器 import java.util.Timer; import java.util.Timer…

云原生时代的轻量级反向代理Traefik

Traefik 是一个用于路由和管理网络流量的反向代理&#xff0c;同时也是一个支持多种协议&#xff08;HTTP、HTTPS、TCP、UDP&#xff09;的负载均衡器。它通过自动服务发现和动态配置&#xff0c;帮助开发者和运维团队轻松管理复杂的应用架构。 Traefik 的主要特点如下&#x…

JavaEE---计算机是如何工作的?

1.了解冯诺依曼体系结构 2.CPU的核心概念,CPU的两个重要指标(核心数和频率) 3.CPU执行指令的流程(指令表,一条一条指令,取指令,解析指令,执行指令) 4.操作系统核心概念(管理硬件,给软件提供稳定的运行环境) 5.进程的概念(运行起来的程序和可执行文件的区别) 6.进程的管理(…

【C++】简单数据类型详解

博客主页&#xff1a; [小ᶻ☡꙳ᵃⁱᵍᶜ꙳] 本文专栏: C 文章目录 &#x1f4af;前言&#x1f4af;字符型&#xff08;char&#xff09;1.1 ASCII 码表 &#x1f4af;整型&#xff08;int&#xff09;2.1 整型的分类2.2 有符号和无符号整型2.3 跨平台差异2.4 整型数据类型…

Vue构建错误解决:(error TS6133)xxx is declared but its value is never read.

TypeScript会检查代码中未使用的变量&#xff0c;如果vscode安装了Vue的语法检查工具&#xff0c;会看到告警提示&#xff0c;再npm run build的时候&#xff0c;这个警告会变成错误 解决方案1&#xff1a;删除定义了未使用的变量 推荐使用这种方案&#xff0c;能保证代码的质…

泷羽sec---shell作业

作业一 写计算器 使用bc命令 需要进行安装bc 代码如下&#xff1a; #!/bin/bash echo "-----------------------------------" echo "输入 f 退出" echo "可计算小数和整数" echo "用法如&#xff1a;1.12.2" echo "------…

混淆零碎知识点

minifyEnabled true //混淆开关 zipAlignEnabled true // Zipalign优化 shrinkResources true // 移除无用的resource文件 &#xff08;必须要混淆开了之后才才可以设置为true&#xff09; proguard-rules.pro 为混淆文件 //整个文件保留 不被混淆 -keep class com.cn…

DeSTSeg: Segmentation Guided Denoising Student-Teacher for Anomaly Detection

DeSTSeg: Segmentation Guided Denoising Student-Teacher for Anomaly Detection 清华、苹果 个人感觉 Introduction 很自然的让读者理解作者问题的提出&#xff0c;也有例子直接证明了这个问题的存在&#xff0c;值得借鉴&#xff01;&#xff01; Related work写的也很不…