iPhone開發之多線程NSThread和NSInvocationOperation
多線程編程是防止主線程堵塞,增加運行效率等等的***方法。而原始的多線程方法存在很多的毛病,包括線程鎖死等。在Cocoa中,Apple提供了NSOperation這個類,提供了一個優秀的多線程編程方法。
本次介紹NSOperation的子集,簡易方法的NSInvocationOperation:
- @implementation MyCustomClass
- -(void)launchTaskWithData:(id)data
- {
- //創建一個NSInvocationOperation對象,并初始化到方法;
- //在這里,selector參數后的值是你想在另外一個線程中運行的方法(函數,Method);
- //在這里,object后的值是想傳遞給前面方法的數據
- NSInvocationOperation *theOp = [[NSInvocationOperation alloc]initWithTarget:self selector:@selector(myTashMethod:) object:data];
- //下面將我們建立的操作"Operation"加入到本地程序的共享的隊列中(加入后方法就會立刻被執行)
- //更多的時候是由我們自己建立“操作”隊列
- [[MyAppDelegate sharedOperationQueue] addOperation:theOp];
- }
- //這個是真正運行在另外一個線程的“方法”
- - (void)myTaskMethod:(id)data
- {
- // Perform the task.
- }
- @end
- //一個NSOperationQueue 操作隊列,就相當于一個線程管理器,而非一個線程。因為你可以設置這個線程管理器內可以并行運行的的線程數量等等。
- //下面是建立并初始化一個操作隊列:
- @interface MyViewController : UIViewController {
- NSOperationQueue* operationQueue;
- //在頭文件中聲明該隊列
- }
- @end
- @implementation MyViewController
- -(id)init
- {
- self = [super init];
- if (self) {
- //初始化操作隊列
- operationQueue = [[NSOperationQueue alloc] init];
- [operationQueue setMaxConcurrentOperationCount:1];
- //在這里限定了該隊列只同時運行一個線程
- //這個隊列已經可以使用了
- }
- return self;
- }
- - (void)dealloc
- {
- [operationQueue release];
- [super dealloc];
- }
- @end
- //簡單介紹之后,其實可以發現這種方法是非常簡單的。很多的時候我們使用多線程僅僅是為了防止主線程堵塞,而NSInvocationOperation就是最簡單的多線程編程,在iPhone編程中是經常被用到的。
- /////////////////////////////////////////////////////////////
- //在主線程里加入一個loading畫面……
- {
- [window addSubview:view_loading];
- //另一個新的線程,可能需要時間進行后臺處理,為了防止主程序在這段時間靜止等待,將后臺處理放在主線程之外的線程執行,執行完以后,通知主線程更新數據。
- [NSThread detachNewThreadSelector:@selector:(init_backup:) toTarget:self withObject:nil];
- }
- //可以通過performSelectorOhMainThread更新UI元素,比如設置進度條等等。***消除loading畫面,載入主View。
- -(void)init_backup:(id)sender
- {
- NSAutorelease* pool = [[NSAutoreleasePool alloc] init];
- //新建的線程需要一個自動釋放池對線程中申請的內存進行管理
- int i = status;
- [self performSelectorOnMainThread:@selector:(show_loading:) wiwithObject::[NSNumber numberWithInt:i] waitUntil Done:NO];
- [view_loading removeFromSuperview];
- [window addSubview:tabcontroller_main.view];
- [pool release];
- }
利用iphone的多線程實現和線程同步
從接口的定義中可以知道,NSThread和大多數iphone的接口對象一樣,有兩種方式可以初始化:
一種使用initWithTarget :(id)target selector:(SEL)selector object:(id)argument,但需要負責在對象的retain count為0時調用對象的release方法清理對象。
另一種則使用所謂的convenient method,這個方便接口就是detachNewThreadSelector,這個方法可以直接生成一個線程并啟動它,而且無需為線程的清理負責。
- #import <UIKit/UIKit.h>
- @interface SellTicketsAppDelegate : NSObject <UIApplicationDelegate>
- {
- int tickets;
- int count;
- NSThread* ticketsThreadone;
- NSThread* ticketsThreadtwo;
- NSCondition* ticketsCondition;
- UIWindow *window;
- }
- @property (nonatomic, retain) IBOutlet UIWindow *window;
- @end
- //SellTicketsAppDelegate.m
- #import "SellTicketsAppDelegate.h"
- @implementation SellTicketsAppDelegate
- @synthesize window;
- - (void)applicationDidFinishLaunching:(UIApplication *)application
- {
- tickets = 100;
- count = 0;
- // 鎖對象
- ticketCondition = [[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];
- //[NSThread detachNewThreadSelector:@selector(run) toTarget:self withObject:nil];
- // Override point for customization after application launch
- [window makeKeyAndVisible];
- }
- - (void)run{
- while (TRUE) {
- //上鎖
- [ticketsCondition lock];
- if(tickets > 0)
- {
- [NSThread sleepForTimeInterval:0.5];
- count = 100 - tickets;
- NSLog(@"當前票數是:%d,售出:%d,線程名:%@",tickets,count,[[NSThread currentThread] name]);
- tickets--;
- }
- else
- {
- break;
- }
- [ticketsCondition unlock];
- }
- -(void)dealloc{
- [ticketsThreadone release];
- [ticketsThreadtwo release];
- [ticketsCondition release];
- [window release];
- [super dealloc];
- }
- @end