本文複製、參考自文章:iOS多線程編程之NSThread的使用 ,主要爲了增強我的對知識的理解和記憶,不作他用。原做者聲明:html
著做權聲明:本文由http://blog.csdn.net/totogo2010/原創,歡迎轉載分享。請尊重做者勞動,轉載時保留該聲明和做者博客連接,謝謝!ios
這裏對原做者的辛勤工做表示感謝!編程
(1)NSThread 數據結構
(2) Cocoa NSOperation多線程
(3) GCD (Grand Central Dispatch)app
這三種方式從上到下,抽象層次逐漸增高,使用也愈來愈簡單。異步
優勢 | 缺點 | |
NSThread | 輕量 | 須要本身管理線程的生命週期,線程同步。線程同步加鎖時,會有必定的系統開銷。 |
NSOperation | 無需關心線程管理,數據同步,能夠把精力放在本身須要的執行操做上 | |
GCD | iOS4.0後出現,以替代NSThread,NSOperation等技術的,很高效、強大 |
(1) 實例方法建立測試
- (id) initWithTarget:(id)target selector:(SEL)selector object:(id) argument
示例: NSThread* myThread = [[NSThread alloc] initWithTarget:self selector:@selector(doSomething:) object:nil]; [myThread start];
(2) NSThread 類方法建立url
+ (void)detachNewThreadSelector:(SEL) aSelector toTarget:(id)aTarget withObject:(id)anArgument 示例: [NSThread detachNewThreadSelector:@selector(doSomething:) toTarget:self withObject:nil];
(3)NSObject 非顯示方法建立spa
+ (void) performSelectorInBackground:(SEL)aSelector withObject:(id)anArgument 示例 [Obj performSelectorInBackground:@selector(doSomething:)withObject:nil];
selector: 線程執行的方法,這個selector只能有一個參數,並且不能有返回值;
target: selector消息發送的對象
argument:傳輸給selector的惟一參數,也能夠是nil
第一種方式會直接建立線程而且開始運行線程,第二種方法是先建立線程對象,而後再運行線程操做,在運行線程操做前能夠設置線程的優先級等線程信息。
(1)在viewDidLoad中建立子線程:
- (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view, typically from a nib. NSThread* thread = [[NSThread alloc] initWithTarget:self selector:@selector(downloadImage:) object:kURL]; // 子線程執行方法 downloadImage [thread start]; // 啓用子線程 }
(2)在線程執行方法 downloadImage 中執行加載數據操做,並使用performSelectorOnMainThread方法 通知主線程進行渲染操做。(線程調回主線程,並傳遞了數據)
- (void)downloadImage:(NSString *) url { NSData* data = [[NSData alloc] initWithContentsOfURL:[NSURL URLWithString:url]]; UIImage* image = [[UIImage alloc] initWithData:data]; if(image == nil) { NSLog(@"image load failed..."); } else { [self performSelectorOnMainThread:@selector(updateUI:) withObject:image waitUntilDone:YES]; // 與主線程通訊,傳遞了image數據 } }
一樣,還可使用:
- (void)performSelector:(SEL)aSelector onThread:(NSThread *)thread withObject:(id)arg waitUntilDone:(BOOL)wait modes:(NSArray *)array
方法來於其餘線程通訊。
(1) 定義public的數據結構,AppDelegate.h中
@interface AppDelegate : UIResponder <UIApplicationDelegate> { int tickets; int count; NSThread* ticketsThreadOne; NSThread* ticketsThreadTwo; NSCondition* ticketsCondition; NSLock* theLock; }
這裏測試使用了NSCondition和NSLock兩種加鎖方法。
(2)初始化, AppDelegate.m中
tickets = 100; count = 0; theLock = [[NSLock alloc] init]; // 鎖對象 ticketsCondition = [[NSCondition alloc] init]; ticketsThreadOne = [[NSThread alloc] initWithTarget:self selector:@selector(run) object:nil]; [ticketsThreadOne setName:@"Thread-1"]; [ticketsThreadOne start]; ticketsThreadTwo = [[NSThread alloc] initWithTarget:self selector:@selector(run) object:nil]; [ticketsThreadTwo setName:@"Thread-2"]; [ticketsThreadTwo start];
(3)執行操做中,加鎖,防止資源搶佔
- (void)run { while (TRUE) { // 上鎖 // [theLock lock]; [ticketsCondition lock]; if (tickets >= 0) { [NSThread sleepForTimeInterval:0.09]; count = 100 -tickets; NSLog(@"當前票數是:%d, 售出:%d, 線程名:%@", tickets, count, [[NSThread currentThread] name]); tickets--; } else { break; } [ticketsCondition unlock]; // [theLock unlock]; } }
NSCondition 可使用 [ticketsCondition wait];等待,並由其餘線程使用[ticketsCondition signal];喚起等待。
咱們還可使用@synchoronized來簡化NSLock的使用,這樣就沒必要顯示建立和調用NSLock對象,而自動建立了一個互斥鎖(mutex lock),防止對資源的搶佔。 以下
obj1 = [[NSObject alloc]init]; // 兩個線程,分別傳遞兩個對象用於原操做標識 obj2 = [[NSObject alloc]init]; ticketsThreadOne = [[NSThread alloc] initWithTarget:self selector:@selector(run:) object:obj1]; [ticketsThreadOne setName:@"Thread-1"]; [ticketsThreadOne start]; ticketsThreadTwo = [[NSThread alloc] initWithTarget:self selector:@selector(run:) object:obj2]; [ticketsThreadTwo setName:@"Thread-2"]; [ticketsThreadTwo start];
- (void)run:(NSObject*) obj { @synchronized(obj) { while (TRUE) { // 上鎖 // [theLock lock]; // [ticketsCondition lock]; int currentTicketNum = [ticketCounter currentTicketNum]; if ( currentTicketNum >= 0) { [NSThread sleepForTimeInterval:0.09]; NSLog(@"當前票數是:%d, 售出:%d, 線程名:%@", currentTicketNum, ticketCounter.initTicketNum - currentTicketNum, [[NSThread currentThread] name]); ticketCounter.currentTicketNum--; } else { break; } // [ticketsCondition unlock]; // [theLock unlock]; } } }