• 【iOS


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

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

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

     5.xcode10如何reset模拟器

    如上所述,在之前的xcode中我们在模拟器用多了有了很多APP后,会点击reset来重置模拟器。可是在xcode10中没有这一选项。那么该如何重置呢?

     

  • 相关阅读:
    GIL锁、进程池和线程池、同步和异步
    线程
    socket编程
    单例模式
    反射、自定义内置方法来定制类的功能、元类
    elasticSearch(一)--数据1
    docker学习整理(三)
    docker学习整理(二)
    docker学习整理(一)
    IDEA 配置mybatis生成代码
  • 原文地址:https://www.cnblogs.com/weicyNo-1/p/10114085.html
Copyright © 2020-2023  润新知