【iOS - 周总结】开发中遇到的小知识点(2018.12.03-2018.12.08)

补充:本文也是拖迟一周才更新的。也是由于项目原因。

时间: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

上面代码还是比较简单的就是需要注意在获取数据后对数据的处理。

 

【iOS - 周总结】开发中遇到的小知识点(2018.12.03-2018.12.08)

上一篇:linux下配置Java和Go环境


下一篇:java保存汉字到mysal乱码