iOS: 天气预报仿写总结
天气预报仿写总结本次项目是仿照iOS原生的天气预报进行仿写, 主要功能包括城市管理, 城市天气数据的展示, 城市搜索,收藏夹页面收藏城市滑动浏览等在这仿写中, 主要采用了MVC的设计模式,笔者认识到了之前对于MVC的应用有很多错误的地方,这次仿写也做了改正天气预报项目是笔者第一次接触网络请求的相关知识,所以开始的时候没有头绪,用好长时间去理解网络请求的步骤, 具体可以看笔者的上一篇博客.在天气预报项目中, 笔者调用的是Open‑Meteo 天气 API, 这个API查询天气不能直接通过城市名称查询, 而是需要通过经纬度查询, 所以我们在查询的时候, 需要先通过城市名称来获取对应城市的经纬度,然后再根据经纬度来定位城市进而获取天气信息搜索这里是根据城市名获取经纬度的APIhttps://geocoding-api.open-meteo.com/v1/search?nameXi%27ancount10languagezhformatjson通过这个API可以对进行模糊搜索, 可以得到城市的名称,经纬度以及所在省份等信息这里搜索笔者是采用了UISearchController, 单独创建了结果更新的视图控制器, 来展示搜索结果, 并在每一次搜索之后更新用于展示结果的UITableView, 关于UISearchController的具体功能笔者之前写过一篇博客专门学习创建UISearchController, 设置搜索结果控制器,homeView.h-(void)setUpNavigation{SearchViewController*vc[[SearchViewController alloc]init];self.searchController[[UISearchController alloc]initWithSearchResultsController:vc];self.searchController.searchResultsUpdatervc;// 模糊背景self.searchController.obscuresBackgroundDuringPresentationYES;// 隐藏导航栏self.searchController.hidesNavigationBarDuringPresentationYES;// 占位文字self.searchController.searchBar.placeholder输入城市名进行搜索;self.searchController.searchBar.delegateself;// 将searchBar 添加到导航栏self.navigationItem.searchControllerself.searchController;// 搜索成一个按钮,点击展开搜索栏// self.navigationItem.preferredSearchBarPlacement UINavigationItemSearchBarPlacementIntegratedButton;self.searchController.delegateself;}在搜索框中输入字符,就会调用搜索结果控制器的- (void)updateSearchResultsForSearchController:(UISearchController *)searchController方法来更新用于结果显示的UITableView,SearchViewController.m-(void)updateSearchResultsForSearchController:(UISearchController*)searchController{self.searchTextsearchController.searchBar.text;if(self.searchText.length0){[self.searchModel.cityArray removeAllObjects];[self.searchView.tableView reloadData];}// // 取消之前尚未执行的延迟调用[NSObject cancelPreviousPerformRequestsWithTarget:selfselector:selector(performSearch)object:nil];// 延迟 0.5 秒后执行实际搜索[selfperformSelector:selector(performSearch)withObject:nil afterDelay:0.5];}-(void)performSearch{if(self.searchText.length0){[self.searchModel.cityArray removeAllObjects];[self.searchView.tableView reloadData];}else{[selfcreateURL];}return;}在这里取消之前的延迟和延迟调用是为了给搜索添加防抖处理用户在搜索框连续输入时会频繁触发updateSearchResultsForSearchController:方法。为防止网络请求过载及响应数据错乱项目中采取了双重防护策略延迟执行使用performSelector:withObject:afterDelay:延迟 0.5 秒执行搜索。若在 0.5 秒内用户继续输入通过cancelPreviousPerformRequests取消前一次未执行的计划任务从而只发起最后一次有效请求。请求 ID 比对忽略过期响应在createURL中生成递增的currentRequestID并在网络请求回调中比对当前 ID。若回调的 ID 与最新 ID 不符则直接丢弃该结果例如,在搜索框中连续输入,每次输入搜索框中的内容发生变化,都会触发搜索结果控制器的UISearchResultsUpdaing协议的- (void)updateSearchResultsForSearchController:(UISearchController *)searchController方法 , 在方法中进行网络请求获取数据从而刷新用于结果显示的UITableView,但是网络请求是异步并发的, 在搜索的时候, 先请求城市A, 后请求城市B, 如果B的服务器响应更快, (比如缓存命中, 数据库查询更简单), B结果会比A更早返回, 于是就会导致A结果后返回覆盖A结果// // 取消之前尚未执行的延迟调用[NSObject cancelPreviousPerformRequestsWithTarget:selfselector:selector(performSearch)object:nil];// 延迟 0.5 秒后执行实际搜索[selfperformSelector:selector(performSearch)withObject:nil afterDelay:0.5];这两段代码中[NSObject cancelPreviousPerformRequestsWithTarget:self selector:selector(performSearch) object:nil];的作用是取消还没有发出的请求操作假设 当输入“北京”后这行代码会将performSearch这个任务延迟 0.5 秒放入一个本地定时器RunLoop。此时网络请求并没有真正发出。如果 0.3 秒后你又输入了“京”字变成“北京”cancelPreviousPerformRequests就会把上一个还没到 0.5 秒的定时任务从本地直接删掉。结果第一个performSearch永远不会被执行网络请求也就不会被创建和发送。所以这句话的本质是“取消即将要执行的操作省下这次不必要的网络请求”而不是“忽略已经发出去的回调”。而[self performSelector:selector(performSearch) withObject:nil afterDelay:0.5];的作用是忽略已经发出的但是返回较晚的旧请求下面是调用自定义的网络管理单例创建网络请求, 然后用请求到的数据刷新结果显示-(void)createURL{// 增加请求IDself.currentRequestID;// 保存本次请求的 IDNSInteger requestIDself.currentRequestID;[[NetworkManager sharedManager]GET:https://geocoding-api.open-meteo.com/v1/searchparameters:{name:self.searchText,count:10,language:zh,format:json}completion:^(NSDictionary*_Nullable json,NSError*_Nullable error){// 检查本次回调是否属于当前的最新请求if(requestID!self.currentRequestID){// 与本次请求不一致, 不响应return;}if(!errorjson){NSArray*resultsjson[results];[self.searchModel.cityArray removeAllObjects];if(results){[self.searchModel.cityArray addObjectsFromArray:results];}[self.searchView.tableView reloadData];}}];}调用API返回的结果是JSON格式的数据(网络响应体中的字符串),NetworkManager会将数据解析为NSDictionary对象, 并以回调参数 JSON 的形式返回给调用方 , 在代码块中再对解析后的数据进行操作,更新数据源dataSource-(UITableViewCell*)tableView:(UITableView*)tableView cellForRowAtIndexPath:(NSIndexPath*)indexPath{UITableViewCell*cell[tableView dequeueReusableCellWithIdentifier:UITableViewCellIDforIndexPath:indexPath];NSDictionary*cityInfoself.searchModel.cityArray[indexPath.row];cell.textLabel.text[NSString stringWithFormat:% -- %,cityInfo[name],cityInfo[admin1]];// cell.textLabel.text self.searchText;returncell;}这是cell根据更新的数据源显示的数据,包括城市的名称和所在省份这里我调用自定义的网络管理单例的GET方法, 并处理了UI的更新然后点击搜索结果的cell可以进行跳转;-(void)tableView:(UITableView*)tableView didSelectRowAtIndexPath:(NSIndexPath*)indexPath{[tableView deselectRowAtIndexPath:indexPath animated:YES];NSDictionary*cityInfoself.searchModel.cityArray[indexPath.row];CGFloat latitude[cityInfo[latitude]doubleValue];CGFloat longitude[cityInfo[longitude]doubleValue];UITableViewCell*cell[tableView cellForRowAtIndexPath:indexPath];CityModel*city[[CityModel alloc]initWithName:cell.textLabel.text Latitude:(latitude)Longitude:(longitude)];WeatherController*vc[[WeatherController alloc]init];vc.citycity;UINavigationController*Nav[[UINavigationController alloc]initWithRootViewController:vc];self.navigationItem.searchController.searchBar.text;[selfpresentViewController:Nav animated:YES completion:nil];}当点击cell的时候,就会获取对应城市的经纬度, 传值到天气详情界面并跳转详情展示在天气详情界面,通过获取到的经纬度继续创建网络请求, 查询城市天气WeatherPageController.m-(void)createURL{NSLog(weather 发出了网络请求);[[NetworkManager sharedManager]GET:https://api.open-meteo.com/v1/forecastparameters:{latitude:(self.city.latitude),longitude:(self.city.longitude),daily:temperature_2m_max,temperature_2m_min,sunrise,sunset,precipitation_sum,wind_speed_10m_max,wind_direction_10m_dominant,weather_code,uv_index_max,hourly:temperature_2m,precipitation,snowfall,weather_code,wind_speed_10m,wind_direction_10m,current:temperature_2m,is_day,precipitation,weather_code,wind_speed_10m,wind_direction_10m,timezone:Europe/Moscow}completion:^(NSDictionary*_Nullable json,NSError*_Nullable error){if(json[current]json[daily]json[hourly]){NSLog(请求到了数据);self.weatherModel.CurrentWeatherModeljson[current];self.weatherModel.DailyWeatherModeljson[daily];self.weatherModel.HourlyWeatherModeljson[hourly];[selfsetUpInterface];[self.weatherView configWithCurrentWeather:self.weatherModel.CurrentWeatherModel];[self.weatherView.tableView reloadData];}else{NSLog(加载失败);NSLog(%,error);UIAlertController*alertController[UIAlertController alertControllerWithTitle:nil message:加载失败, 请检查网络preferredStyle:UIAlertControllerStyleAlert];UIAlertAction*okAction[UIAlertAction actionWithTitle:确定style:UIAlertActionStyleDefault handler:^(UIAlertAction*_Nonnull action){[selfpressBack];}];[alertController addAction:okAction];[selfpresentViewController:alertController animated:YES completion:nil];}}];}在展示页面,笔者使用UITableView自定义cell来显示, 主要分为几个板块当前天气, 未来24小时天气, 未来7天天气这些数据都是通过API返回的,NetworkManage将返回的JSON数据解析为NSDictionary对象, 我们可以直接接收并直接从字典中获取收藏城市的添加和展示要做到在详情展示界面可以添加城市到收藏栏,还要在首页显示收藏的城市信息, 这里笔者使用了全局单例,创建了一个收藏夹类来存储收藏的城市当在详情界面点击添加按钮的时候,就会在收藏夹中添加一个城市信息,包括城市的名称, 所在省份以及经纬度同时在点击添加按钮的时候就会通过通知传值让首页显示添加的城市,避免了返回首页再进行网络请求获取数据导致显示异常-(void)pressAdd{HomeModel*homeModel[HomeModel shareInstance];if(!homeModel.homeCities){homeModel.homeCities[[NSMutableArray alloc]init];}if([homeModel.homeCities indexOfObject:self.city]NSNotFound){[homeModel addCityToSave:self.city];self.navigationItem.rightBarButtonItemself.deleteButton;UIAlertController*alertController[UIAlertController alertControllerWithTitle:nil message:添加成功preferredStyle:UIAlertControllerStyleAlert];UIAlertAction*okAction[UIAlertAction actionWithTitle:确定style:UIAlertActionStyleDefault handler:^(UIAlertAction*_Nonnull action){[[NSNotificationCenter defaultCenter]postNotificationName:ReleadNotification object:selfuserInfo:nil];NSLog(OK);}];[alertController addAction:okAction];[selfpresentViewController:alertController animated:YES completion:nil];}else{UIAlertController*alertController[UIAlertController alertControllerWithTitle:nil message:该城市已经添加收藏夹, 重复添加preferredStyle:UIAlertControllerStyleAlert];UIAlertAction*okAction[UIAlertAction actionWithTitle:确定style:UIAlertActionStyleDefault handler:^(UIAlertAction*_Nonnull action){NSLog(OK);}];[alertController addAction:okAction];[selfpresentViewController:alertController animated:YES completion:nil];}}

相关新闻

PyCharm运行自动跳转测试的排查与解决方法

PyCharm运行自动跳转测试的排查与解决方法

1. PyCharm运行直接跳转Test的根源分析遇到PyCharm一运行就自动执行测试用例的情况,本质上是因为IDE的运行配置被意外修改或项目结构存在特殊标记。根据我处理过的上百个同类案例,这种情况通常由以下三种原因导致:默认运行配置被覆盖&#xf…

2026/10/17 16:16:35 阅读更多 →
系统大小端模式判定(联合体标准法)

系统大小端模式判定(联合体标准法)

目录 一、判定核心原理 二、标准判定代码(面试 / 工程通用) 三、底层可视化解析 1. 小端系统存储逻辑 2. 大端系统存储逻辑 四、联合体核心优势 五、速记结论 六、主流系统场景 一、判定核心原理 大小端是 CPU 多字节数据的内存存储规则&#x…

2026/10/19 2:53:52 阅读更多 →
计算机字节序(大小端)核心原理与代码实战

计算机字节序(大小端)核心原理与代码实战

目录 第一篇:字节序本质|CPU、寄存器、存储器核心关系 一、核心硬件分工 二、字节序诞生原理 三、大小端可视化定义 第二篇:核心代码验证|存储逻辑与 printf 输出机制 一、验证代码 二、小端环境标准输出 三、核心逻辑解析…

2026/10/12 19:32:46 阅读更多 →

最新新闻

论文查重与AI率检测全攻略:原理、工具与降重技巧

论文查重与AI率检测全攻略:原理、工具与降重技巧

每年到了毕业论文提交季,最让人焦虑的往往不是论文本身有多难写,而是“查重”那一关。更麻烦的是,近两年几乎所有高校都多了一条新指标:AI生成内容检测。也就是说,论文不仅要控制重复率,还要控制“AI率”。…

2026/10/19 6:07:40 阅读更多 →
AI生成论文查重工具与实用通过技巧:降重和去AI痕迹全解析

AI生成论文查重工具与实用通过技巧:降重和去AI痕迹全解析

现在的论文写作已经不太一样了。以前大家最担心的是“重复率太高”,特地用各种改写工具对付查重系统;现在又多了一件事,很多学校、期刊不仅要看重复率,还会用AI检测工具判断论文是不是“大模型生成的”。于是“AI生成论文查重工具…

2026/10/19 6:07:40 阅读更多 →
软件测试工程师转型AI教育:技能迁移与90天实操指南

软件测试工程师转型AI教育:技能迁移与90天实操指南

2026年了,软件测试从业者的职业讨论里,AI教育这个词出现的频率越来越高。它不再只是教育行业内部的话题,而是被很多测试同行看作“新出路”的关键词。所谓新路径,不是让你丢掉测试底盘去卷算法,也不是让你从零学做课件…

2026/10/19 6:07:40 阅读更多 →
测试工程师转型AI教育:能力迁移与实操路径

测试工程师转型AI教育:能力迁移与实操路径

去年底我参加了一个业内的线上交流,主题是测试工程师的技能树更新。会场上有位同行问了一个很现实的问题:如果自动化测试工具越来越智能,测试用例可以自动生成、自动维护,那我们这批人还剩下什么?当时我没法给出一个让…

2026/10/19 6:07:40 阅读更多 →
图表设计实战指南:从配色、布局到团队规范,提升图表可读性

图表设计实战指南:从配色、布局到团队规范,提升图表可读性

1. 从"diagram-design"这个标题里能读出什么第一次看到"diagram-design"这个标题,我脑子里蹦出来的第一个念头是:这大概率不是一个单纯的"画图工具"项目,而是一套关于"图表设计"的方法论或者设计系统…

2026/10/19 6:07:40 阅读更多 →
双目三维重建从标定到体积测量:误差链分析及5大避坑指南

双目三维重建从标定到体积测量:误差链分析及5大避坑指南

简介:一套聚焦三维重建完整链路的学习型示例工程,面向计算机视觉入门者以及机器人导航、增强现实方向的开发者,解决摄像头标定、双目立体校正和点云体积计算中的核心算法落地问题,整体使用C实现,便于理解底层计算过程。…

2026/10/19 6:06:39 阅读更多 →

日新闻

频率跟踪型PWM电源设计:臭氧发生器谐振点漂移与软开关实现

频率跟踪型PWM电源设计:臭氧发生器谐振点漂移与软开关实现

简介:本资源为电源技术方向的学术研究文档,聚焦介质阻挡放电型臭氧发生器电源的频率跟踪型PWM控制策略,面向电力电子、高压电源及臭氧应用领域的科研人员与工程技术人员。针对负载呈容性、等效电容随外加电压升高而增大、谐振频率随之漂移的难…

2026/10/19 0:00:47 阅读更多 →
Vibe Coding 遇上 TaoToken:把开发者思维圣殿的灵感流接入统一 Key 通道

Vibe Coding 遇上 TaoToken:把开发者思维圣殿的灵感流接入统一 Key 通道

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/19 0:00:47 阅读更多 →
HundredCV-Chat话题建模实战教程:利用4,871个内置话题标签构建主题分析系统

HundredCV-Chat话题建模实战教程:利用4,871个内置话题标签构建主题分析系统

【免费下载链接】HundredCV-Chat 项目地址: https://ai.gitcode.com/hf_mirrors/Jax-dan/HundredCV-Chat 点击查看 免费下载 HundredCV-Chat 是一个由 100 位青年简历数据开发而来的中文多轮对话数据集,共包含 24,750 组日常闲聊对话和 4,871 个话题标签…

2026/10/19 0:00:47 阅读更多 →

周新闻

基于GMM的语音识别系统原理与MATLAB实现详解

基于GMM的语音识别系统原理与MATLAB实现详解

说到基于高斯混合模型(GMM)的语音识别系统,很多人第一反应就是一堆数学公式,觉得门槛很高。但如果你真的在MATLAB里把它落地跑通,会发现核心其实就是三件事:把声音变成特征向量,用GMM给每个类别…

2026/10/18 0:00:55 阅读更多 →
数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理这四个字听起来挺唬人,但落到具体操作上,无非就是让计算机按你的想法“摆弄”像素。我在一个模拟项目X里用了一套特别经典的基础处理流程:对图像做反白、改调色板、彩色转灰度,最后把像素数据导出成txt文件。单看每一…

2026/10/18 0:00:55 阅读更多 →
机器人大脑技术盘点:具身智能的感知、决策与数据闭环

机器人大脑技术盘点:具身智能的感知、决策与数据闭环

如果你的信息流最近也天天刷到“机器人大脑”这个词,你会发现一个很有意思的现象:每个人说的“大脑”根本不是同一个东西。有人指的是大语言模型,有人指的是运动控制系统,还有人指的是能理解物理世界的端到端模型。在2026年这个时…

2026/10/19 1:30:52 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/19 2:54:50 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/17 17:22:31 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/18 12:16:16 阅读更多 →