欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 教育 > 高考 > 天气预报仿写总结

天气预报仿写总结

2025/11/9 14:01:42 来源:https://blog.csdn.net/2301_80095702/article/details/140886818  浏览:    关键词:天气预报仿写总结

目录

前言

首页

搜索页

详情页

浏览页


前言

这周学习了iOS中简单的网络请求,并完成了天气预报的仿写,这篇博客来做一下总结。天气预报主要要实现四个界面,接下来分四个界面分别讲解一下。

首页

首页的布局就是上方两个很简单的控件添加按钮和“天气”logo,下面一个动态变化的数据视图tableview。

这个数据视图的每一个单元格都需要一个城市实时的天气信息。

我的思路是数据视图的行数由一个数组的数量来确定,这个数组存放的是城市的名字,并且对于每一个城市的名字,都要申请网络请求来获得城市ID,进一步获得当前天气状态和七天的天气状态,从而获得数据视图的数据。

在进行更新数据源这一步时,我遇到的一个问题就是网络请求的异步,由于网络请求的异步机制,在有多个网络请求时,程序不是按顺序执行,申请完一个请求再进行下一个,而是多个网络请求同时在后台进行,因此在网络请求的回调里获取完某一项数据更新数据源时,就总会出现数据源为空或者数组越界的情况。

我的解决思路是:分为两种情况,第一种是需要网络请求有序完成,我采取网络请求嵌套的方法,例如获取城市天气需要先获得城市ID,那么我就在获取城市ID的回调中来获取所有与天气有关的数据;第二种是网络请求可以无序完成,那我就在每一个网络请求的回调里都做一次判断,当我所需要的数据都不为空并且数组元素数量达到要求时,进行数据视图的reloadData。

这里给出获取城市ID的API和获取实时天气的API以做示范

- (void)createURLForCityID {[self.cityIDMutableArray removeAllObjects];for (NSString* city in self.cityMutableArray) {//处理字符NSString* urlString = [NSString stringWithFormat:@"https://geoapi.qweather.com/v2/city/lookup?location=%@&key=34e1f7a3ef5544d393fcafaea08f0f1b&range=cn", city];NSLog(@"%@", urlString);urlString = [urlString stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLQueryAllowedCharacterSet]];//创建URLNSURL* url = [NSURL URLWithString:urlString];//创建请求类NSURLRequest* request = [NSURLRequest requestWithURL:url];//创建会话NSURLSession* session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration] delegate:self delegateQueue:[NSOperationQueue mainQueue]];//根据会话创建任务NSLog(@"12%@", urlString);NSURLSessionTask* dataTask = [session dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {if (error) {NSLog(@"无法获取城市ID");} else {NSDictionary* dictionary = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:&error];if (error) {NSLog(@"无法获取城市ID");} else {NSArray* array = dictionary[@"location"];NSDictionary* nowcity = array[0];NSLog(@"%@", nowcity[@"id"]);[self.cityIDMutableArray addObject:nowcity[@"id"]];NSLog(@"citycount:%d %d",self.cityMutableArray.count, self.cityIDMutableArray.count);if (self.cityMutableArray.count == self.cityIDMutableArray.count) {[self createURLForNow];[self createURLForDay];}}}}];[dataTask resume];}
}
- (void)createURLForNow {[self.tempMutableArray removeAllObjects];[self.stateMutableArray removeAllObjects];for (NSString* cityID in self.cityIDMutableArray) {//处理字符NSString* urlString = [NSString stringWithFormat:@"https://devapi.qweather.com/v7/weather/now?location=%@&key=34e1f7a3ef5544d393fcafaea08f0f1b", cityID];urlString = [urlString stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLQueryAllowedCharacterSet]];//创建URLNSLog(@"%@", urlString);NSURL* url = [NSURL URLWithString:urlString];//创建请求类NSURLRequest* request = [NSURLRequest requestWithURL:url];//创建会话NSURLSession* session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration] delegate:self delegateQueue:[NSOperationQueue mainQueue]];//根据会话创建任务NSURLSessionTask* dataTask = [session dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {if (error) {NSLog(@"无法获取天气信息");} else {NSDictionary* dictionary = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:&error];if (error) {NSLog(@"无法获取天气信息");} else {NSDictionary* nowWeather = dictionary[@"now"];[self.tempMutableArray addObject:[nowWeather[@"temp"] stringByAppendingString:@"°C"]];if (self.lowAndHighMutableArray.count == self.cityMutableArray.count && self.stateMutableArray.count == self.cityMutableArray.count && self.tempMutableArray.count == self.cityMutableArray.count) {[self.tableView reloadData];}}}}];[dataTask resume];}
}

搜索页

搜索页面的布局其实也很简单,一个searchBar和一个同样动态变化的数据视图tableview。

这个界面要实现一个模糊搜索的功能,这里其实获取城市ID的API是有模糊搜索的功能的,所以只需要在调用API申请网络数据后,将得到的城市数据放入数组里,再重新加载数据视图就可以了

详情页

这个界面的布局相对比较复杂,但其实也还好,就是在数据视图上实现五个cell,关于布局的部分只是繁琐难度并不大就不多说了。这个界面需要接收上一个界面点击某个单元格时那个城市的ID(注意一定要是ID,笔者一开始传的是城市的名字,出现的问题就是当出现同名城市时,往往只能获取固定某一个城市的天气),在获取完ID后,再在详情页申请网络请求获取天气信息。笔者这里判定网络请求完成的条件非常复杂,这里给出我的判定条件

if (self.lowAndHigh != NULL && self.state != NULL && ![self.temp isEqualToString:@""] && !self.tableView && self.tempForHoursMutableArray.count == 24 && self.hoursMutableArray.count == 24 && self.daysMutableArray.count == 7 && self.tempForDaysMutableArray.count == 7 && self.sunrise != NULL && self.sunset != NULL && self.see != NULL && self.rain != NULL && self.iconForHoursMutableArray.count == 24 && self.iconForDaysMutableArray.count == 7) {[self createBackgroundView:self.state];[self createATableview];//NSLog (@"tianshu:%ld",self.tempForDaysMutableArray.count);//NSLog(@"tempOK");}

 这个界面还要实现一个将城市添加到主页的功能,那么就获取当前城市ID,使用通知传值传到首页,遍历首页ID数组查重,如未重复,则在城市和城市ID数组中添加当前城市名和ID即可。(注意:查重时一定要使用城市ID,因为可以存在不同身份同名的城市,例如:黑龙江省的西安和陕西西安应该是可以同时出现在首页的)

浏览页

浏览页的本质就是一个滚动视图,只是这个滚动视图上的图片不是通过image类型获取的,而是直接拿的视图控制器的view属性,多次创建不同的详情页视图控制器,再将详情页的view放入滚动视图就可以实现。需要注意的是,这里需要将详情页视图控制器作为浏览页的子视图控制器,再将他的视图view放入滚动视图,否则就会出现一系列错位问题。

除此之外,添加子视图控制器和添加子视图控制器视图的顺序也会导致代码运行的差别,如果先添加视图,那么在添加视图时会调用一次子视图控制器的viewWillApear,当父视图控制器调用viewWillApear时,又会调用一次子视图控制器的viewWillApear。颠倒顺序的话,则子视图控制器只调用一次viewWillApear。

    self.scrollview = [[UIScrollView alloc] init];self.scrollview.frame = CGRectMake(0, 0, [UIScreen mainScreen].bounds.size.width, [UIScreen mainScreen].bounds.size.height);self.scrollview.contentSize = CGSizeMake([UIScreen mainScreen].bounds.size.width * self.cityMutableArray.count, 800);self.scrollview.delegate = self;self.scrollview.pagingEnabled = YES;NSLog(@"%ld", self.cityMutableArray.count);for (int i = 0; i < self.cityMutableArray.count; i++) {CGFloat xOffset = i * self.view.bounds.size.width;NSLog(@"%lf", xOffset);DetailViewController* detailViewController = [[DetailViewController alloc] init];//detailViewController.exitButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];detailViewController.cityName = self.cityMutableArray[i];detailViewController.cityID = self.cityIDMutableArray[i];detailViewController.view.frame = CGRectMake(xOffset, 0, self.view.bounds.size.width, self.view.bounds.size.height);[self addChildViewController:detailViewController];[self.scrollview addSubview:detailViewController.view];}self.scrollview.contentOffset = CGPointMake(_nowPage * [UIScreen mainScreen].bounds.size.width, 0);

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

热搜词