知乎日报前三周总结)
首页
上述图片是笔者首页的完成效果,首页中并没有特别难的部分,主要的难点就是上拉刷新以及网络申请的问题,最上方使用了一个无线轮播视图,这里的实现并不是很难,主要的问题还是关于网络申请的部分。
网络申请
网络申请笔者这里采用的是AFNetWroking以及YYModel完成的网络申请,这些内容才之前的博客中都有过讲解,这里就不多进行赘述,这里主要还面临的问题就是网络异步的问题,这里笔者使用GCD来解决这个问题,但是GCD的原理等笔者还没有学习,这里先使用来解决网络异步的问题。
objectivec
- (void)loadImages:(long) a {
// 使用 dispatch_group 来等待所有图片加载完成
dispatch_group_t imageLoadGroup = dispatch_group_create();
NSMutableArray* arrimage = [NSMutableArray array];
for (NSDictionary *dic in self->_arrStories[a]) {
NSArray* arr = dic[@"images"];
NSURL *imageurl = [NSURL URLWithString:arr[0]];
UIImageView *iview = [[UIImageView alloc] init];
dispatch_group_enter(imageLoadGroup); // 进入组
[iview sd_setImageWithURL:imageurl
placeholderImage:[UIImage imageNamed:@"placeholder.png"]
options:SDWebImageRefreshCached
completed:^(UIImage * _Nullable image, NSError * _Nullable error, SDImageCacheType cacheType, NSURL * _Nullable imageURL) {
if (error) {
NSLog(@"加载图片失败: %@", error.localizedDescription);
} else {
NSLog(@"图片加载成功");
}
dispatch_group_leave(imageLoadGroup); // 离开组
}];
[arrimage addObject:iview];
}
[self->_arr_image addObject:arrimage];
// 在所有图片加载完成后设置主视图
dispatch_group_notify(imageLoadGroup, dispatch_get_main_queue(), ^{
[self loadtopImages]; // 设置主视图
});
}
- (void)loadtopImages {
// 使用 dispatch_group 来等待所有图片加载完成
dispatch_group_t imageLoadGroup = dispatch_group_create();
for (NSDictionary *dic in self->_arr_top_stories) {
NSString* arr = dic[@"image"];
NSLog(@"%@", arr);
NSURL *imageurl = [NSURL URLWithString:arr];
UIImageView *iview = [[UIImageView alloc] init];
dispatch_group_enter(imageLoadGroup); // 进入组
[iview sd_setImageWithURL:imageurl
placeholderImage:[UIImage imageNamed:@"placeholder.png"]
options:SDWebImageRefreshCached
completed:^(UIImage * _Nullable image, NSError * _Nullable error, SDImageCacheType cacheType, NSURL * _Nullable imageURL) {
if (error) {
NSLog(@"加载图片失败: %@", error.localizedDescription);
} else {
NSLog(@"图片加载成功");
}
dispatch_group_leave(imageLoadGroup); // 离开组
}];
[self->_arr_topimage addObject:iview];
}
// 在所有图片加载完成后设置主视图
dispatch_group_notify(imageLoadGroup, dispatch_get_main_queue(), ^{
[self setupMainView]; // 设置主视图
});
}
根据上述代码可以看出,笔者这里采用一个请求嵌套一个请求的方法,避免最后更新主视图时出现空数组的情况,导致报错。
上拉刷新
这里我通过使用滚动视图的协议来判断是否tableview已经滑动到了底端,如果已经滑动到了底端,就进行网络申请,获取前一天的数据,这样就达到了一个上拉刷新的效果。
objectivec
CGFloat y = scrollView.contentOffset.y;
CGFloat contentHeight = scrollView.contentSize.height;
CGFloat height = scrollView.bounds.size.height;
if (y + height >= contentHeight + 10) {
[self Gaindate];
}
-(void) Gaindate {
if(self.action)
return;
self.action = YES;
[self.mainview.active startAnimating];
NSString *strweb = @"https://news-at.zhihu.com/api/4/news/before/";
// 使用 stringByAppendingFormat 创建一个新的字符串
strweb = [strweb stringByAppendingFormat:@"%@", [self->_date lastObject]];
NSLog(@"%@", strweb);
id manager = [Manager shareManager];
[manager URLString:strweb NetWorkWithData:^(ModelShuju * _Nonnull mainModel) {
NSDictionary *dic = [mainModel yy_modelToJSONObject];
NSArray *arr = dic[@"stories"];
[self.date addObject:dic[@"date"]];
// 在主线程中更新 UI
dispatch_async(dispatch_get_main_queue(), ^{
[self->_arrStories addObject:arr];
[self loadImages1:(self->_arrStories.count - 1)];// 加载图片
[self getURL:(self->_arrStories.count - 1)];
});
} error:^(NSError * _Nonnull error) {
NSLog(@"error:%@", error.localizedDescription);
}];
}
通过这两个函数就可以刷新前一天的数据。
详情页
上图即笔者的详情页,这个页面中主要的问题就是左右滑动时进行对webView的申请,还有就是对于首页和详情页之间的相互传递信息,当详情页刷新到一个没有出现的信息时,需要使用传值将信息传递回首页,同步更新内容。
WKWebView
WKWebView使用时需要添加头文件:
objectivec
#import <WebKit/WebKit.h>
而后使用其实比较简单:
objectivec
NSString *urlString = _strurl[_count];
NSURL *url = [NSURL URLWithString:urlString];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
[_webview loadRequest:request];
如上所示,就可以加载出webview了。
左右滑动
笔者这里左右滑动的逻辑上还存在一点问题,无法一次滑动多个页面跳过中间的进行webview的申请,后期还需要对这里进行一个升级,这里先展示笔者现有的逻辑。
objectivec
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
if (fabs(scrollView.contentOffset.x - self.lastContentOffset.x) > fabs(scrollView.contentOffset.y - self.lastContentOffset.y)) {
scrollView.contentOffset = CGPointMake(scrollView.contentOffset.x, self.lastContentOffset.y);
} else {
self.lastContentOffset = scrollView.contentOffset; // 更新位置
}
CGFloat widthNow = self.mainview.scroll.contentOffset.x;
CGFloat widthbegin = self.count * 393;
CGFloat width = self.mainview.scroll.contentSize.width;
NSInteger cha = width - widthNow;
NSInteger cha1 = widthbegin - widthNow;
// NSLog(@"%ld", (long)cha1);
if(cha == 393 && !_Right) {
NSLog(@"开始申请");
_Right = YES;
self.mainview.scroll.contentSize = CGSizeMake(width + 393, 719);
_webview = [[WKWebView alloc] initWithFrame:CGRectMake(widthNow, 0, 393, 719)];
_webview.navigationDelegate = self;
if(_countright < _strurl.count) {
[self gainextra:_countright];
NSString *urlString = _strurl[_countright];
_countright++;
NSLog(@"URL String: %@", urlString);
[self gainWebview:urlString];
} else {
NSLog(@"重新申请");
[self gaindate];
}
}
if(cha1 == 393 && !_Right) {
NSLog(@"开始申请");
_Right = YES;
_webview = [[WKWebView alloc] initWithFrame:CGRectMake(widthNow, 0, 393, 719)];
_webview.navigationDelegate = self;
[self gainextra:_countleft];
NSString *urlString = _strurl[_countleft];
_count--;
_countleft--;
NSLog(@"URL String: %@", urlString);
[self gainWebview:urlString];
}
}
笔者这里通过判断滑动的位置来进行网络申请,申请webview展示在滚动视图上,但是由于我的限制,不可以跳过中间的页面进行申请后面的页面,后面会更改逻辑上的问题,从而使得更加完善。
首页和详情页的数据传输
这里主要需要传输的就是当我在详情页获取到新的一天的数据,即首页中未刷新的前一天的数据时,需要将这个数据传输会首页,让首页进行一个tableview的刷新,从而使得更加的流畅和合理。其实对于首页传输到详情页而言,则更为简单,笔者这里直接使用了属性传值的方法,就不过多进行赘述了。
笔者这里使用了通知传值的方法,当我获得到新的一天的数据时,直接传递回首页。
objectivec
NSDictionary* dictionary = @{@"stories":[self->_arrStories lastObject],@"date":[self->_arrdate lastObject]};
[[NSNotificationCenter defaultCenter] postNotificationName:@"inform" object:nil userInfo:dictionary];
首页中:
objectivec
[[NSNotificationCenter defaultCenter]addObserver:self selector:@selector(receiveNoticed:) name:@"inform" object:nil];
}
- (void)receiveNoticed:(NSNotification*)sender {
[_arrStories addObject:sender.userInfo[@"stories"]];
[_date addObject:sender.userInfo[@"date"]];
[self loadImages111:(_arrStories.count - 1)];
}
这样就可以相互传递信息,避免了两个页面中数据不同步导致逻辑不甚合理的问题了。
总结
后面的内容笔者还在写,对于评论区的展开功能还没有写完,仅申请到了数据,还有收藏的知识点没有学习,后面的内容笔者后期还会总结,这次就先总结这么多内容。