补充:本文也是拖迟一周才更新的。也是由于项目原因。
时间:2018.12.03-2018.12.08
1.在主线程操作UI
在开发中我们一般只在主线程操作UI,但是在一些方法中我们会调用一下UI处理。这时候就会报出一些错误警告等。
1. UI API called from background thread Group
在本周开发中我就遇到这个问题,在一个异步网络请求中,刷新UI结果报警告。解决方法如下:
dispatch_async(dispatch_get_main_queue(), ^{
[self.tableView.mj_header endRefreshing];
[self.tableView reloadData];
});
之前我也遇到过这个问题,就是在开启指纹解锁后,根据结果来控制是否打开指纹解锁开关。也是这样解决的。
2.在带有tabbar的APP中打开子界面返回时tabbar图片位置上移。
如上所述,在一个带有tabbar的APP中,打开子界面,子界面不含有tabbar,在从子界面返回时,有时候会发现tabbar上的item的图片上移,有的还会超出tabbar范围。这个问题很好解决。
[[UITabBar appearance] setTranslucent:NO];
只要设置上上面这行代码就可以。但是有时候不设置也可以。有点迷。如果你出现了这个问题就可以设置试试。
3.WKWebView的使用。
WKWebView是iOS8之后推出的一个类。在本周我是打算写一个通用web页。由于项目基于iOS9之后开发,就使用了WKWebView。直接附上代码。代码里有注释。
#import "CustomWebViewController.h" #import <WebKit/WebKit.h> #import <JavaScriptCore/JavaScriptCore.h> @interface CustomWebViewController ()<WKNavigationDelegate, WKUIDelegate, WKScriptMessageHandler> @property (nonatomic, strong) WKWebView *webview; @end @implementation CustomWebViewController - (void)viewDidLoad { [super viewDidLoad]; } #pragma mark - Base Action//初始化视图 - (void)initContentView { WKWebViewConfiguration *configuration = [[WKWebViewConfiguration alloc] init]; configuration.preferences = [WKPreferences new]; configuration.userContentController = [WKUserContentController new]; /* // 需要将被js调用的方法注册进去 [configuration.userContentController addScriptMessageHandler:self name:@"selectWayPay"]; [configuration.userContentController addScriptMessageHandler:self name:@"ios_logIn"]; */ self.webview = [[WKWebView alloc] initWithFrame:self.view.frame configuration:configuration]; self.webview.navigationDelegate = self; self.webview.UIDelegate = self; [self.view addSubview:self.webview]; if (!WCYIsEmpty(self.urlStr)) { NSURL *url = [NSURL URLWithString:self.urlStr]; NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url cachePolicy:NSURLRequestReloadIgnoringLocalCacheData timeoutInterval:60]; [self.webview loadRequest:request]; } } #pragma mark - 设置标题 - (void)setWebTitle { self.navigationItem.title = self.webview.title; } #pragma mark - 页面消失 清除缓存 - (void)viewDidDisappear:(BOOL)animated{ [super viewDidDisappear:animated]; [self deleteWebCache]; } - (void)deleteWebCache { NSSet *websiteDataTypes = [NSSet setWithArray:@[WKWebsiteDataTypeDiskCache,WKWebsiteDataTypeMemoryCache]]; NSDate *dateFrom = [NSDate dateWithTimeIntervalSince1970:0]; [[WKWebsiteDataStore defaultDataStore] removeDataOfTypes:websiteDataTypes modifiedSince:dateFrom completionHandler:^{ }]; } #pragma mark - WKScriptMessageHandler //WKScriptMessageHandler协议方法 - (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message { // 收到 js的交互 // 需要在 configuration生成是注册 这种方法message.body必填 } #pragma mark - WKUIDelegate - (void)webView:(WKWebView *)webView runJavaScriptAlertPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(void))completionHandler { // js 里面的alert实现,如果不实现,网页的alert函数无效 } - (void)webView:(WKWebView *)webView runJavaScriptConfirmPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(BOOL))completionHandler { // js 里面的alert实现,如果不实现,网页的alert函数无效 , } #pragma mark - WKNavigationDelegate /* 1 在请求发送之前,决定是否跳转 2 页面开始加载时调用 3 在收到响应后,决定是否跳转 4 内容开始加载时调用 5 接收到服务器跳转请求之后调用(不一定调用该方法) 5 页面加载完成时调用 6 请求失败时调用 */ // 在请求发送之前,决定是否跳转 -> 该方法如果不实现,系统默认跳转。如果实现该方法,则需要设置允许跳转,不设置则报错。 // decisionHandler(WKNavigationActionPolicyAllow); // 该方法执行在加载界面之前 // Terminating app due to uncaught exception ‘NSInternalInconsistencyException‘, reason: ‘Completion handler passed to -[ViewController webView:decidePolicyForNavigationAction:decisionHandler:] was not called‘ - (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler { /* //允许跳转 decisionHandler(WKNavigationActionPolicyAllow); //不允许跳转 // decisionHandler(WKNavigationActionPolicyCancel); NSLog(@"在请求发送之前,决定是否跳转。 1"); */ NSURL *URL = navigationAction.request.URL; NSString *scheme = [URL scheme]; UIApplication *app = [UIApplication sharedApplication]; // 打电话 if ([scheme isEqualToString:@"tel"]) { if ([app canOpenURL:URL]) { [app openURL:URL]; // 一定要加上这句,否则会打开新页面 decisionHandler(WKNavigationActionPolicyCancel); return; } } } // 页面开始加载时调用 - (void)webView:(WKWebView *)webView didStartProvisionalNavigation:(WKNavigation *)navigation { NSLog(@"页面开始加载时调用。 2"); } // 页面加载完成时调用 - (void)webView:(WKWebView *)webView didFinishNavigation:(null_unspecified WKNavigation *)navigation { [self setWebTitle]; NSLog(@"页面加载完成时调用。 5"); } // 请求失败时调用 - (void)webView:(WKWebView *)webView didFailProvisionalNavigation:(null_unspecified WKNavigation *)navigation withError:(NSError *)error { NSLog(@"error1:%@",error); } -(void)webView:(WKWebView *)webView didFailNavigation:(WKNavigation *)navigation withError:(NSError *)error { NSLog(@"error2:%@",error); } //内容返回时调用,得到请求内容时调用(内容开始加载) -> view的过渡动画可在此方法中加载 - (void)webView:(WKWebView *)webView didCommitNavigation:( WKNavigation *)navigation { NSLog(@"内容返回时调用,得到请求内容时调用。 4"); } // 在收到响应后,决定是否跳转(同上) // 该方法执行在内容返回之前 - (void)webView:(WKWebView *)webView decidePolicyForNavigationResponse:(WKNavigationResponse *)navigationResponse decisionHandler:(void (^)(WKNavigationResponsePolicy))decisionHandler { //允许跳转 decisionHandler(WKNavigationResponsePolicyAllow); //不允许跳转 // decisionHandler(WKNavigationResponsePolicyCancel); NSLog(@"在收到响应后,决定是否跳转。 3"); } // 接收到服务器跳转请求之后调用 - (void)webView:(WKWebView *)webView didReceiveServerRedirectForProvisionalNavigation:(null_unspecified WKNavigation *)navigation { NSLog(@"接收到服务器跳转请求之后调用 不一定有"); } -(void)webViewWebContentProcessDidTerminate:(WKWebView *)webView { NSLog(@"webViewWebContentProcessDidTerminate"); }@end
参考文档:博客一
4.设置tableview 索引
直接上代码
#import "SelectCityViewController.h" @interface SelectCityViewController ()<UITableViewDelegate,UITableViewDataSource>@property (nonatomic, strong) UITableView *tableView; @property (nonatomic, strong) NSMutableArray *indexArray; // index 数组 @property (nonatomic, strong) NSMutableDictionary *dataDic; @end @implementation SelectCityViewController - (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view. } #pragma mark - Base Action //初始化数据 - (void)initContentData { self.indexArray = [NSMutableArray array]; self.dataDic = [NSMutableDictionary dictionary]; } //初始化视图 - (void)initContentView { [self changeNavi]; [self.view addSubview:self.tableView]; [self configTable]; } - (void)changeNavi { self.title = @"选择"; } #pragma mark - 加载 刷新 - (void)configTable { CFRefreshGifHeader *mj_header = [CFRefreshGifHeader headerWithRefreshingBlock:^{ [self loadNewData]; }]; mj_header.mj_h = 80; self.tableView.mj_header = mj_header; [self.tableView.mj_header beginRefreshing]; } - (void)loadNewData { [WCYNetWorking getWithUrl:@"链接" refreshCache:YES success:^(id response) { // 刷新 清除之前数据 [self.dataDic removeAllObjects]; [self.indexArray removeAllObjects]; NSArray *array = [CityListModel mj_objectArrayWithKeyValuesArray:response]; for (CityListModel *city in array) { NSString *firstChar = [self firstCharactor:city.name]; if ([self.dataDic containsObjectForKey:firstChar]) { // 包含 NSMutableArray *array = [NSMutableArray arrayWithArray:[self.dataDic objectForKey:firstChar]]; [array addObject:city]; [self.dataDic setObject:array forKey:firstChar]; } else { // 不包含 NSArray *array = @[city]; [self.dataDic setObject:array forKey:firstChar]; } } self.indexArray = [NSMutableArray arrayWithArray:[[self.dataDic allKeys] sortedArrayUsingSelector:@selector(compare:)]]; [self.tableView reloadData]; [self.tableView.mj_header endRefreshing]; } fail:^(NSError *error) { [self.view makeToast:[error.userInfo objectForKey:@"NSLocalizedDescription"]]; [self.tableView.mj_footer endRefreshing]; }]; } #pragma mark - UITableViewDataSource - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { return self.indexArray.count; } - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { NSArray *array = [self.dataDic objectForKey:self.indexArray[section]]; return array.count; } - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { return AdaptedWidth(45); } - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { UITableViewCell * cell = [tableView dequeueReusableCellWithIdentifier:GET_CLASS_NAME(UITableViewCell)]; if (!cell) { cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:GET_CLASS_NAME(UITableViewCell)]; } NSArray *array = [self.dataDic objectForKey:self.indexArray[indexPath.section]]; CityListModel *model = array[indexPath.row]; cell.textLabel.text = model.name; cell.textLabel.textColor = [UIColor colorWithHexString:@"081E3C"]; cell.textLabel.font = AdaptedFontSize(14); return cell; } // 索引 - (NSArray<NSString *> *)sectionIndexTitlesForTableView:(UITableView *)tableView { return self.indexArray; } - (NSInteger)tableView:(UITableView *)tableView sectionForSectionIndexTitle:(NSString *)title atIndex:(NSInteger)index { return index; } #pragma mark - UITableViewDelegate - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { [tableView deselectRowAtIndexPath:indexPath animated:YES]; } #pragma mark - Lazy Setter- (UITableView *)tableView { if (!_tableView) { _tableView = [[UITableView alloc] initWithFrame:CGRectMake(0, 0, SCREENT_WIDTH, SCREENT_HEIGHT - TopNavHeight) style:UITableViewStylePlain]; _tableView.delegate = self; _tableView.dataSource = self; _tableView.separatorStyle = UITableViewCellSeparatorStyleNone; _tableView.sectionHeaderHeight = 0.001; _tableView.sectionFooterHeight = 0.001; _tableView.backgroundColor = VIEW_BACKGROUNDCOLOR; _tableView.tableHeaderView = self.tableHead; // //修改右边索引的背景色 // _tableView.sectionIndexBackgroundColor = [UIColor greenColor]; //修改右边索引字体的颜色 _tableView.sectionIndexColor = [UIColor colorWithHexString:@"081E3C"]; // //修改右边索引点击时候的背景色 // _tableView.sectionIndexTrackingBackgroundColor = [UIColor orangeColor]; } return _tableView; } #pragma mark - 右侧索引所需方法 - (NSString *)firstCharactor:(NSString *)aString{ //转成了可变字符串 NSMutableString *str = [NSMutableString stringWithString:aString]; //先转换为带声调的拼音 CFStringTransform((CFMutableStringRef)str,NULL, kCFStringTransformMandarinLatin,NO); //再转换为不带声调的拼音 CFStringTransform((CFMutableStringRef)str,NULL, kCFStringTransformStripDiacritics,NO); //转化为大写拼音 NSString *pinYin = [str capitalizedString]; //获取并返回首字母 return [pinYin substringToIndex:1]; } @end
上面代码还是比较简单的就是需要注意在获取数据后对数据的处理。