天气预报仿写总结

目录

前言

首页

搜索页

详情页

浏览页


前言

这周学习了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]];
        //创建URL
        NSURL* 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]];
        //创建URL
        NSLog(@"%@", 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);
  • 10
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
要在VSCode中仿写天气预报,你可以按照以下步骤进行操作: 1. 创建一个新的HTML文件:在VSCode中,点击左上角的"文件",选择"新建文件",然后将文件保存为一个HTML文件,例如"weather.html"。 2. 编写HTML结构:在HTML文件中,编写基本的HTML结构,包括头部、主体和脚部。可以使用HTML标签如`<head>`、`<body>`和`<footer>`来组织页面。 3. 添加CSS样式:使用CSS来美化页面的外观。你可以在`<head>`标签内添加`<style>`标签,并在其中编写CSS样式代码,例如设置背景颜色、字体样式等。 4. 添加JavaScript代码:使用JavaScript来获取天气数据并显示在页面上。你可以在`<body>`标签内添加`<script>`标签,并在其中编写JavaScript代码。可以使用第三方的天气API来获取天气数据,例如OpenWeatherMap API。 5. 获取天气数据:在JavaScript代码中,使用AJAX或Fetch等技术来向天气API发送请求,并获取返回的天气数据。根据API的文档,你可以了解如何构造请求URL和处理返回的JSON数据。 6. 显示天气信息:将获取到的天气数据解析并显示在页面上。你可以使用DOM操作来创建HTML元素,并将天气信息插入到相应的元素中。 7. 调试和测试:在VSCode中,你可以使用内置的调试工具来调试JavaScript代码,以确保代码的正确性和功能的正常运行。你还可以在浏览器中打开HTML文件,进行测试和查看效果。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值