你好,歡迎來到IOS教程網

 Ios教程網 >> IOS編程開發 >> IOS開發綜合 >> iOS 多線程編程(十五、RunLoop簡單介紹)

iOS 多線程編程(十五、RunLoop簡單介紹)

編輯:IOS開發綜合

一:什麼是RunLoop

(1)從字面意思看,運行循環、跑圈。 (2)保持程序持續運行,處理App中的各類事件包括觸摸事件、定時器事件、Selector事件。 (3)節省CPU資源,提高程序的性能,該做事的時候做事,該休息的時候休息。

二:RunLoop與線程

  (1)每條線程都有唯一的一個與之對應的RunLoop對象。 (2)主線程的RunLoop已經自動創建好了,子線程的RunLoop需要主動創建。 (3)RunLoop在第一次獲取時創建,在線程結束時候銷毀。

三:RunLoop相關類

Core Foundation中關於RunLoop的5個類 1:CFRunLoopRef 2:CFRunLoopModeRef ,CFRunLoopModeRef代表RunLoop的運行模式,一個RunLoop包含若干個運行模式,即一個RunLoop包含若干個Mode,每個Mode又包含若干個Source/Timer/Observer,每次RunLoop啟動時,只能指定其中一個Mode,這個Mode被稱作CurrentMode,如果需要切換Mode,只能退出Loop,再重新指定一個Mode進入。系統默認注冊了5個Mode: (1)kCFRunLoopDefaultMode:App的默認的Mode,通常線程是在這個Mode下運行 (2)UITrackingRunLoopMode:界面跟蹤Mode,用於ScrollView追蹤觸摸滑動,保證界面滑動時不受其它Mode影響 (3)UIInitializationRunLoopMode:在剛啟動App時進入的第一個Mode,啟動完成後就不再使用 (4)GSEventReceiveRunLoopMode:接收系統事件的內部Mode,通常用不到。 (5)kCFRunLoopCommonMode:這是一種占位用的Mode,不是一種真正的Mode。 3:CFRunLoopTimerRef (1)CFRunLoopTimerRef是基於時間的觸發器。 (2)基本上說的就是NSTimer,它會受到runloop的Mode的影響。 (3)GCD的定時器不受RunLoop的mode的影響。 關於定時器和runloopMode的關系如下代碼
//
//  ViewController.m
//  CFRunLoopTimerRef
//
//  Created by fe on 2016/10/25.
//  Copyright © 2016年 fe. All rights reserved.
//

#import "ViewController.h"

@interface ViewController ()
@property (nonatomic , strong) dispatch_source_t timer;
@end

@implementation ViewController

-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
    
    [self GCDTimer];

}


-(void)timer1
{
    /*
     第一種定時器用法,這種方式創建的定時器,
     系統默認添加到NSRunLoop中的NSDefaultRunLoopMode模式中,
     但是當用戶和應用交互發生觸摸滑動等事件時,
     RunLoop的模式會切換到UITrackingRunLoopMode,
     此時定時器就不再工作,因為定時器只在,默認被添加到的NSDefaultRunLoopMode
     模式下工作。
     */
    [NSTimer scheduledTimerWithTimeInterval:2.0 target:self selector:@selector(go) userInfo:nil repeats:YES];
}
-(void)timer2
{
    /*
     第二種定時器用法,這種方式創建的定時器,如果添加到NSRunLoop,
     並設置RunLoop模式為NSDefaultRunLoopMode,
     當用戶和應用交互發生觸摸滑動等事件時,
     RunLoop的模式會切換到UITrackingRunLoopMode,
     此時定時器就不再工作,因為定時器只在NSDefaultRunLoopMode模式下工作。
     
     如果把用這種方式創建的定時器,添加到NSRunLoop,
     並設置RunLoop模式為UITrackingRunLoopMode,
     在這種情況下,只有當用戶和應用交互發生觸摸滑動等事件時,
     定時器才會工作。
     
     為了解決以上兩種RunLoop運行模式造成的定時器,定時不准的問題。
     我們可以把定時器添加到RunLoop並設置運行模式為NSRunLoopCommonModes.
     在這種運行模式下,不管是默認狀態,還是當用戶和應用交互發生觸摸滑動等事件時。
     定時器都可以正常工作。
     */
    //1:創建定時器
    NSTimer *timer = [NSTimer timerWithTimeInterval:2.0 target:self selector:@selector(go) userInfo:nil repeats:YES];
    
    //2.1:把定時器添加到RunLoop中,定時器在NSDefaultRunLoopMode模式下工作。
    //[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode];
    
    //2.2:把定時器添加到RunLoop中,定時器在UITrackingRunLoopMode模式下工作。
    //[[NSRunLoop currentRunLoop] addTimer:timer forMode:UITrackingRunLoopMode];
    
    //2.3
    /*
     把定時器添加到RunLoop中,設置模式為NSRunLoopCommonModes,
     定時器在UITrackingRunLoopMode模式和NSDefaultRunLoopMode模式下都工作。
     
     NSRunLoopCommonModes是一種標記模式,被打上這種標記的模式有以下兩種
     0 : contents = "UITrackingRunLoopMode"
     2 : contents = "kCFRunLoopDefaultMode"
     */
    [[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];
    NSLog(@"---------%@",[NSRunLoop currentRunLoop]);
    

}
-(void)GCDTimer
{
    /*
     使用GCD的定時器,不會受到RunloopMode的影響。
     */
    
    
    //0:創建隊列
    dispatch_queue_t queue = dispatch_queue_create("cn.520.www", DISPATCH_QUEUE_CONCURRENT);
    
    //1:創建一個GCD定時器
    dispatch_source_t timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue);
    self.timer = timer;
    
    //2:設置定時器的開始時間,間隔時間,精確度。精准度一般填0,表示沒有誤差。
    dispatch_source_set_timer(timer, DISPATCH_TIME_NOW, 2.0 * NSEC_PER_SEC, 0 * NSEC_PER_SEC);
    
    //3:定時器要調用的方法。
    dispatch_source_set_event_handler(timer, ^{
        NSLog(@"----------%@",[NSThread currentThread]);
    });
    
    //4:啟動定時器。
    dispatch_resume(timer);
}
-(void)go
{
    NSLog(@"-----------");
}
@end

  4:CFRunLoopSourceRef (1)CFRunLoopSourceRef是事件源(輸入源),分為兩種。 (2)Source0:非基於Port的,用於用戶主動觸發的事件。 (3)Source1:基於Port的,通過內核和其它線程相互發送消息。 5:CFRunLoopObserverRef (1)CFRunLoopObserverRef是觀察者,能夠監聽RunLoop狀態的改變。 (2)可以監聽的時間點有一下幾個
/* Run Loop Observer Activities */
    typedef CF_OPTIONS(CFOptionFlags, CFRunLoopActivity) {
        kCFRunLoopEntry = (1UL << 0),//即將進入loop
        kCFRunLoopBeforeTimers = (1UL << 1),//即將處理timer
        kCFRunLoopBeforeSources = (1UL << 2),//即將處理Source
        kCFRunLoopBeforeWaiting = (1UL << 5),//即將進入休眠
        kCFRunLoopAfterWaiting = (1UL << 6),//即將從休眠中喚醒
        kCFRunLoopExit = (1UL << 7),//即將推出RunLoop
        kCFRunLoopAllActivities = 0x0FFFFFFFU//監聽所有狀態
    };
和CFRunLoopObserverRef相關的代碼如下:
-(void)observer
{
    /*
     第一個參數:開辟內存空間
     第二個參數:監聽runloop的什麼事件
     第三個參數:是否持續監聽
     第四個參數:優先級
     第五個參數:回掉
     */
    CFRunLoopObserverRef observer = CFRunLoopObserverCreateWithHandler(CFAllocatorGetDefault(), kCFRunLoopAllActivities, YES, 0, ^(CFRunLoopObserverRef observer, CFRunLoopActivity activity) {
        
        switch (activity){
           case kCFRunLoopEntry:
                NSLog(@"--runloop即將進入循環--");
                break;
                
            case kCFRunLoopBeforeTimers:
                NSLog(@"--runloop將要處理timer--");
                break;
                
            case kCFRunLoopBeforeSources:
                NSLog(@"--runloop將要處理sources--");
                break;
                
            case kCFRunLoopBeforeWaiting:
                NSLog(@"--runloop將要進入休眠--");
                break;
                
            case kCFRunLoopAfterWaiting:
                NSLog(@"--runloop休眠結束即將進入循環--");
                break;
                
            case kCFRunLoopExit:
                NSLog(@"--runloop退出循環--");
                break;
                
            default:
                break;
        }
    
    });
    
    
    
    /*
     第一個參數:要監聽哪一個runloop
     第二個參數:監聽者
     第三個參數:要監聽runloop在哪種運行模式下的狀態
     */
    CFRunLoopAddObserver(CFRunLoopGetCurrent(), observer, kCFRunLoopDefaultMode);

   
}


           
  1. 上一頁:
  2. 下一頁:
蘋果刷機越獄教程| IOS教程問題解答| IOS技巧綜合| IOS7技巧| IOS8教程
Copyright © Ios教程網 All Rights Reserved