記這段時間的iOS面試(未完待續)

前言

從事iOS也有幾年了,以前總覺得,我入行時間比別人更久,比別人更加厲害,在群里總是能夠幫助其他人,解決其他人的問題,覺得自己有在進不.
不知道什么時候開始,我的心態就變了,覺得自己很厲害,覺得那些入行時間比自己短的肯定不如自己,甚至自己自以為是,覺得很長時間不敲代碼也能很好的面對,總是覺得自己很厲害了,看不起那些初入的人,自己卻沒想過自己不也是這么過來的,這段時間在面試,也反省了自己,覺得自己的心態真的要重新調整,不能繼續這樣下去,雖然自己真的有工作經驗,但是技術跟經驗是兩回事,你有經驗,不代表你的技術好,為什么那些經驗只有1年或者2年的能找到比你更好的工作,我以前總是想,人家只是運氣好,可是好的工作意味著對人才的篩選更加注重,難道就那么容易糊弄過去嗎?是有一些運氣好,但更多的是自己本身的技術,基礎很重要,面試很難看得出你經驗如何,但是卻能夠在聊天的過程中,知道你的基礎怎樣,你連基礎都掌握不牢固,企業怎么相信你能夠在其他方面做的更好?我會把我覺得有意義的都記錄下來,希望能夠自勉.

正文

Runtime和NSRunloop

下面是我自己的自我理解,不會寫太多理論性的東西,如果有不對,請拋磚
Runtime在OC中是比較概念的理解,又叫運行時,在項目運行的時候調用的一些機制,最主要的是調用消息機制.
NSRunloop才是能夠用于開發者手中的,不能跟Runtime混為一談,或許覺得兩者比較相似,但其實根本不一樣,一種是概念,一種是實用的函數.
一個線程只有一個runloop,主線程默認就開著一個runloop,子線程如果想一直保留,就需要用runloop去保留子線程,不然當子線程走完之后就會自動注銷.
runloop的作用:

  • 讓程序一直運行,能夠隨時跟用戶交互
  • 能夠決定程序什么時候執行什么事件
  • 調節,比如scrollview和nstimer
  • 節省CPU
    上面經常用到的,就有一個調節,或許會發現在用scrollview滑動的時候,nstimer是停止狀態,其實并不是停止,這都是runloop的問題,只要調節好這兩個就可以同時處理,這里用到的是調節,不是新建個runloop,一個線程只能有一個runloop,所以不能說新建個runloop,runloop類似一個消息通知的機制,runloop只能接受一種模式,如果更換模式,就需要暫停再繼續,簡單來說,只需要把nstimer的添加到nsrunloop里面的CommonModes模式下就可以了,大概是這樣寫的:
NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(timerTick:) userInfo:nil repeats:YES];  
[[NSRunLoop currentRunLoop]addTimer:timer forMode:NSRunLoopCommonModes];

還有在子線程保持怎么做,AFN的源碼中有寫

AFNetworking中RunLoop的創建

多線程

目前常用的也就這么幾種: NSThread,GCD, NSOperation

  • NSThread目前主要用于調試,比如[NSThread currentThread],來查看線程.
  • GCD,這個是最常用的多線程,能夠設置任務和隊列,意思就是按照你設定的任務去執行多線程的操作.
    • 任務有兩種模式,一種是同步sync一種是異步async,同步是指在主線程執行,異步是指在子線程執行不會阻塞主線程,一般用于除了更新UI其他的情況下使用.
    • 隊列分為串行隊列和并行隊列,串行就是一個一個的執行,并行是指分配到多條線程去一起執行.(分配到多個是指在異步的情況下)
      創建主隊列:
dispatch_queue_t queue = dispatch_get_main_queue();

創建串行隊列或者并行隊列

// 這里入參里面的第一個參數是線程名稱,一般我是沒起名字的,后面的參數來覺得你是串行還是并行隊列,null是串行
dispatch_queue_t queue = dispatch_queue_create(0, NULL);
// DISPATCH_QUEUE_CONCURRENT是創建并行隊列
dispatch_queue_t queue = dispatch_queue_create(0, DISPATCH_QUEUE_CONCURRENT);

但其實在實用中一般都是用全局并行隊列

// 這是最常用的異步線程處理的方法,一般兩個參數直接寫0就可以
dispatch_async(dispatch_get_global_queue(0, 0), ^{
        NSLog(@"%@",[NSThread currentThread]);
    });

隊列組,意思是可以把很多隊列放在一個組里面一起執行,等全部執行完畢后回調通知完成隊列.這個用的地方也比較多.

//1.創建隊列組
    dispatch_group_t group = dispatch_group_create();
    //2.創建隊列
    dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
    
    //3.多次使用隊列組的方法執行任務, 只有異步方法
    //3.1.執行3次循環
    dispatch_group_async(group, queue, ^{
        for (NSInteger i = 0; i < 3; i++) {
            NSLog(@"group-01 - %@", [NSThread currentThread]);
        }
    });
    
    //3.2.主隊列執行8次循環
    dispatch_group_async(group, dispatch_get_main_queue(), ^{
        for (NSInteger i = 0; i < 8; i++) {
            NSLog(@"group-02 - %@", [NSThread currentThread]);
        }
    });
    
    //3.3.執行5次循環
    dispatch_group_async(group, queue, ^{
        for (NSInteger i = 0; i < 5; i++) {
            NSLog(@"group-03 - %@", [NSThread currentThread]);
        }
    });
    
    //4.都完成后會自動通知
    dispatch_group_notify(group, dispatch_get_main_queue(), ^{
        NSLog(@"完成 - %@", [NSThread currentThread]);
    });

上面代碼來自關于iOS多線程,你看我就夠了

  • NSOperation,這個我自己用的不多,資料從其他地方找來并按照自己的理解寫的.
    NSOperation是GCD的封裝,OC語言來說更容易看懂,但是很多人多數還是用的GCD. NSOperation是任務,還有一個NSOperationQueue是隊列,其實跟GCD差不多的.不同的是創建好任務和線程后需要自己執行start方法來啟動,也可以執行cancel來取消.
// 這是創建一個block的任務,默認在當前線程執行
NSBlockOperation *operation = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"%@",[NSThread currentThread]);
    }];
// 但是如果添加多個任務就會變成其他任務分配到子線程去執行,并行線程
for (NSInteger i = 0; i < 5; i++) {
          [operation addExecutionBlock:^{
              NSLog(@"第%ld次:%@", i, [NSThread currentThread]);
          }];
      }
    [operation start];

不過這樣是不科學的,特么會影響到主線程的任務怎么能用?這個時候就需要用到隊列NSOperationQueue,只要設置好隊列就不怕上面的情況發生.

// 這是創建一個主線程的隊列
NSOperationQueue *queue = [NSOperationQueue mainQueue];
// 只要是alloc創建的,就是其他線程
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
// 按照上面的代碼,只需要改下就可以
NSBlockOperation *operation = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"%@",[NSThread currentThread]);
    }];
//隊列添加任務就可以了,隊列是什么類型任務就會按照隊列的類型去執行,不需要start方法,已經默認帶了.
[queue addOperation:operation];

默認都是并行隊列,NSOperation有個屬性是maxConcurrentOperationCount,設置每次執行的最大數量,如果設置為1就是串行隊列,一條一條執行.
NSOperation還有一個依賴的方法,就是可以指定先完成哪個任務再完成這個任務,[任務2 addDependency:任務1];意思是任務1完成后才會執行任務2.

網絡

網絡庫很多,iOS本身有NSURLConnection和NSURLSession,第三方目前用的最多的就是AFNetworking啦.

  • NSURLConnection:這是一個最老的庫.
// 創建一個url
NSURL *url = [NSURL URLWithString:@"http://www.abc.com"];
// 把url丟進去request里面,其實這里應該加多一個UTF8的編碼比較妥當
    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
// 異步執行網絡請求,得到一個nsdata的回調數據
    [NSURLConnection sendAsynchronousRequest:request queue:[[NSOperationQueue alloc] init] completionHandler:^(NSURLResponse * _Nullable response, NSData * _Nullable data, NSError * _Nullable connectionError) {
        //...
    }];
  • NSURLSession:iOS7以上可以使用,目前流行的庫, AFNetworking3.0開始也只支持NSURLSession.可見實用性是多大.
    NSURLSession有個很重要的屬性,就是Task,task有3個類型,數據類型,上傳類型,還有一個下載類型.
    NSURLSession的網絡請求方法:
// 獲得NSURLSession對象
    NSURLSession *session = [NSURLSession sharedSession];
    
    // 創建請求
    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:@"http://www.abc.com"]];
    request.HTTPMethod = @"POST"; // 請求方法
    request.HTTPBody = [@"abc" dataUsingEncoding:NSUTF8StringEncoding]; // 請求體
    
    // 創建任務
    NSURLSessionDataTask *task = [session dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
        //打印解析后的json數據
        NSLog(@"%@", [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:nil]);
    }];
    
    // 啟動任務
    [task resume];

除了block的形式還有通過代理的形式,代理的好處是可以分化代碼,而且能夠比較清晰的知道進度到哪里.

// 接收到服務器的響應
-(void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveResponse:(NSURLResponse *)response completionHandler:(void (^)(NSURLSessionResponseDisposition))completionHandler;
// 接收到服務器的數據(可能會被調用多次)
-(void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveData:(NSData *)data;
// 請求成功或者失敗(如果失敗,error有值)
-(void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error;
  • AFNetworking:最常用的第三方庫
    相對來說因為AFNetworking使得網絡請求的操作變得簡單,能夠通過很簡單的代碼就實現網絡請求,具體可以看github官網,因為官方啟用了NSURLConnection,所以AFNetworking也啟用了,目前一般請求代碼是這樣:
AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
    [manager POST:@"http://www.abc.com" parameters:nil progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
        
    } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
        
    }];
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容