网站搭建的,网页制作 培训,青海网站制作,免费建站的软件这几天一直在进行知乎日报的仿写#xff0c;仿写过程中积累了许多实用的开发经验#xff0c;并对MVC有了更深的了解#xff0c;特撰此篇作以总结 目录 第一周将网络请求封装在一个单例类Manager中SDWebImage库的简单使用运用时间戳处理当前时间自定义NavigationBar 第二周在…这几天一直在进行知乎日报的仿写仿写过程中积累了许多实用的开发经验并对MVC有了更深的了解特撰此篇作以总结 目录 第一周将网络请求封装在一个单例类Manager中SDWebImage库的简单使用运用时间戳处理当前时间自定义NavigationBar 第二周在UITableView的section之间的headerView上画UIWKWebView的使用WKWebView网页加载不出来线程问题 第三周attempting to add unsupported attribute: (null)错误FMDB数据库的简单使用WebView界面无限右滑 源码 第一周
将网络请求封装在一个单例类Manager中
由于知乎日报所请求的API较多若将网络请求三板斧直接写在Controller中会代码十分冗杂干脆直接将AFNetWorking和JSONModel封装到一个全局的Manager单例类中在Manager类中进行网络请求和数据解析不同的API写成不同的方法具体实现看这篇博客
typedef void(^LatestStoriesBlock)(LatestStoriesModel* latestStoriesModel);
typedef void(^BeforeStoriesModelBlock)(StoriesModel* beforeStoriesModel);
typedef void(^StoriesContentBlock)(StoriesContentModel* storiesContentModel);
typedef void(^StoriesExtraContentBlock)(StoriesExtraContentModel* storiesExtraContentModel);
typedef void(^ErrorBlock)(NSError* error);interface Manager : NSObject//单例实例(instancetype)sharedManager;//请求最新消息
- (void)requestTopStoriesData: (LatestStoriesBlock)success failure: (ErrorBlock)failure;//缓存网络图片(void)setImage: (id)imageView WithString: (NSString *)string;//请求指定日期的消息内容
- (void)requestBeforeDate: (NSString *)date beforeStoriesData: (BeforeStoriesModelBlock)success failure: (ErrorBlock)failure;//加载Web网页在WebView中
- (void)setWebView: (WKWebView *)webView WithString: (NSString *)string;//请求指定网页的内容主要为了获取share_url
- (void)requestWebContentWithID: (NSString *)string StoriesContentData: (StoriesContentBlock)success failure: (ErrorBlock)failure;//请求制定网页的额外内容
- (void)requestExtraContentWithID: (NSString *)string StoriesExtraContentData: (StoriesExtraContentBlock)success failure: (ErrorBlock)failure;end解析下来的数据用Block传值【iOS】属性传值、代理传值委托、通知传值、KVO传值、Block传值、单例传值的方式在Controller中接收
SDWebImage库的简单使用
使用WebImage库主要是为了缓存网络图片并加载在UIImageView上只需在loadRequest:方法中传入指定的NSURL (void)setImage:(UIImageView *)imageView WithString:(NSString *)string {string [string stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLQueryAllowedCharacterSet]];NSURL* url [NSURL URLWithString:string];[imageView sd_setImageWithURL: url placeholderImage: [UIImage imageNamed: placeholder.png]];
}运用时间戳处理当前时间 时间戳是指格林威治时间1970年01月01日00时00分00秒北京时间1970年01月01日08时00分00秒起至现在的总秒数。 处理方法单独写在一个工具类中方便管理
interface DateModel : NSObject (NSTimeInterval)getTimestampWithTimeString: (NSString *)timeString;(NSString *)getMonthWithTimeString: (NSString *)timeString;(NSString *)getDayWithTimeString: (NSString *)timeString;(NSString *)getDateWithTimeString: (NSString *)timeString;(NSString *)getBeforeDateWithTimeString: (NSString *)timeString;end获取时间戳方法
//传入时间格式20230917(NSTimeInterval)getTimestampWithTimeString: (NSString *)timeString {NSDateFormatter* dateFormatter [[NSDateFormatter alloc] init];[dateFormatter setDateFormat: YYYYMMdd];NSDate* date [dateFormatter dateFromString: timeString];NSTimeInterval timeStamp [date timeIntervalSince1970];return timeStamp;
}通过时间戳处理指定时间 NSDateFormatter* dateFormatter [[NSDateFormatter alloc] init];//YYYY获取年份 MM获取月份 dd获取日份 //当然也可以混用如MM月dd日这样就会得到一个指定格式的时间字符串[dateFormatter setDateFormat: MM];NSTimeInterval timeStamp [self getTimestampWithTimeString: timeString];NSDate* date [NSDate dateWithTimeIntervalSince1970: timeStamp];NSString* string [dateFormatter stringFromDate: date];自定义NavigationBar 在push页面过程中使用系统的NavigationBar会发现UI是逐渐消失的而知乎日报App是第二个页面直接覆盖过去的想不到什么实现这种效果的巧妙方法这里我直接在NavigationBar的位置直接粘上一个UIView并在当前控制器隐藏NavigationBar
- (void)viewWillAppear:(BOOL)animated {[self.navigationController setNavigationBarHidden: YES animated: YES];
}- (void)viewWillDisappear:(BOOL)animated {[self.navigationController setNavigationBarHidden: NO animated: YES];
}这两个方法涉及UIViewController的生命周期【iOS】ViewController生命周期 第二周
在UITableView的section之间的headerView上画UI tableView提供了这样一个协议方法自定义section
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section {if (section 1) {UIView* view [[UIView alloc] init];UILabel* dateLabel [[UILabel alloc] init];dateLabel.textColor [UIColor grayColor];dateLabel.font [UIFont boldSystemFontOfSize: 15];dateLabel.text [DateModel getDateWithTimeString: self.beforeDateArray[section - 1]];[view addSubview: dateLabel];UIView* grayView [[UIView alloc] init];grayView.backgroundColor [UIColor colorWithRed: 231.0 / 255 green: 231.0 / 255 blue: 231.0 / 255 alpha: 1];[view addSubview: grayView];[dateLabel makeConstraints:^(MASConstraintMaker *make) {make.left.equalTo(view.left).offset(MINIGAP);make.centerY.equalTo(view.centerY);}];[grayView makeConstraints:^(MASConstraintMaker *make) {make.height.equalTo(1);make.left.equalTo(dateLabel.right).offset(MINIGAP);make.right.equalTo(view.right);make.centerY.equalTo(view.centerY);}];return view;} else {return nil;}
}但section之间的距离跟返回view的高度是没有关系的要想消除分区之间的留白给以下属性赋值即可 self.tableView.sectionHeaderTopPadding 0;WKWebView的使用
只需传入NSRequest即可在webView上加载web网页
- (void)setWebView:(WKWebView *)webView WithString:(NSString *)string {//NSLog(%, string);NSMutableURLRequest *request [NSMutableURLRequest requestWithURL:[NSURL URLWithString: string]];[webView loadRequest: request];
}WKWebView网页加载不出来
大概查了一下
出现加载不出来本质原因是如果没在plist文件中设置App Transport Security Settings的话加载https链接肯定是加载不出来的第一次加载不出来产生了缓存第二次再去加载也加载不出来了可以尝试一下就知道了
线程问题
网络请求是在Controller中调用的请求下来的数据会赋值给View的各种属性但请求是需要时间的如果在viewDidLoad里面先初始化view那么还没等数据请求下来UI就已经布局那么只会显示空白的UI控件未解决这一问题用到了GCD的一个方法 dispatch_async(dispatch_get_main_queue(), ^{[self sendViewStories: latestStoriesModel];[self createTopImages];[self setViewAndModel];[self requestBeforeStoriesWithDate: self.latestStoriesModel.date];});第三周 attempting to add unsupported attribute: (null)错误
使用masonry设置约束时约束冲突或约束不全
解决方法就是补充必要的约束或者调整调用顺序
FMDB数据库的简单使用
FMDB库将C语言风格的MySqlite数据库封装成了OC风格的方法而且操作比C语言文件操作更容易
以点赞集合存储相应网页的ID为例实现了数据库的增删改查
#pragma mark 点赞操作
- (void)createStoriesLikeSet {NSString* doc [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];NSString* fileName [doc stringByAppendingPathComponent: likeDatabase.sqlite];NSLog(%, fileName);self.likeDatabase [FMDatabase databaseWithPath: fileName];if ([self.likeDatabase open]) {BOOL result [self.likeDatabase executeUpdate: CREATE TABLE IF NOT EXISTS likeDatabase (idLabel text NOT NULL)];if (result) {FMResultSet* resultSet [self.likeDatabase executeQuery: SELECT * FROM likeDatabase];while([resultSet next]) {[self.storiesLikeSet addObject:[resultSet stringForColumn: idLabel]];}NSLog(create table succeed);} else {NSLog(fail to open database);}[self.likeDatabase close];}
}- (void)saveStoriesLikeSet {if ([self.likeDatabase open]) {for (NSString* ID in self.storiesLikeSet) {FMResultSet* resultSet [self.likeDatabase executeQuery: SELECT * FROM likeDatabase WHERE idLabel ?, ID];if (![resultSet next]) {BOOL result [self.likeDatabase executeUpdate: INSERT INTO likeDatabase (idLabel) VALUES (?), ID];if (result) {NSLog(insert table succeed);} else {NSLog(insert table error);}}}[self.likeDatabase close];}
}- (void)deleteLikeSetWithID:(NSString*)ID {if ([self.likeDatabase open]) {BOOL result [self.likeDatabase executeUpdate: delete from likeDatabase WHERE idLabel ?, ID];if (result) {NSLog(delete table succeed);} else {NSLog(delete table error);}[self.likeDatabase close];}
}WebView界面无限右滑
向右加载新一天的消息时主页的tableViewCell也要更新这里使用了通知中心进行消息传递 if (self.scrollView.contentOffset.x Screen_WIDTH * self.numberOfStories) {[[NSNotificationCenter defaultCenter] postNotificationName: upDateRight object: nil];return;}滑到了新增加的画布时先通知首页更新一天数据
//更新首页
[[NSNotificationCenter defaultCenter] addObserver: self selector: selector(upDateRight) name: upDateRight object: nil];- (void) upDateRight {StoriesModel* storiesModel [self.beforeStoriesModelArray lastObject];NSString* beforeDate storiesModel.date;[self requestBeforeStoriesWithDate: beforeDate];
}然后将更新后的数据传回WebView相关页面加载新的Web
- (void)requestBeforeStoriesWithDate: (NSString *)date {[self.manager requestBeforeDate: date beforeStoriesData:^(StoriesModel * _Nonnull beforeStoriesModel) {if (!self.beforeStoriesModelArray) {self.beforeStoriesModelArray [[NSMutableArray alloc] init];}[self.beforeStoriesModelArray addObject: beforeStoriesModel];//NSLog(%, beforeStoriesModel.date);dispatch_async(dispatch_get_main_queue(), ^{[self sendViewStories: beforeStoriesModel];self.mainView.isLoading NO;[self.mainView.tableView reloadData];NSMutableArray* storiesArray [[NSMutableArray alloc] init];for (Stories* stories in beforeStoriesModel.stories) {[storiesArray addObject: stories.id];}[[NSNotificationCenter defaultCenter] postNotificationName: upDateRight-Two object:nil userInfo: {value : storiesArray}];});} failure:^(NSError * _Nonnull error) {NSLog(请求过往消息失败);}];
}但这里面遇到了数组越界问题向右滑着滑着就访问到了不存在的索引目前尚未解决
源码
Github DEMO
这里先挂一个半成品之后会想办法解决这个bug并尝试实现评论区、收藏夹和夜间模式等。