1. 程式人生 > >【iOS - 周總結】開發中遇到的小知識點(2018.12.03-2018.12.08)

【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

上面程式碼還是比較簡單的就是需要注意在獲取資料後對資料的處理。