多線程編程是防止主線程堵塞,增加運行效率等等的最佳方法。而原始的多線程方法存在很多的毛病,包括線程鎖死等。在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
@interface SellTicketsAppDelegate : NSObject
{
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];
}