iPhone開(kāi)發(fā)之多線程N(yùn)SThread和NSInvocationOperation
多線程編程是防止主線程堵塞,增加運(yùn)行效率等等的***方法。而原始的多線程方法存在很多的毛病,包括線程鎖死等。在Cocoa中,Apple提供了NSOperation這個(gè)類(lèi),提供了一個(gè)優(yōu)秀的多線程編程方法。
本次介紹NSOperation的子集,簡(jiǎn)易方法的NSInvocationOperation:
- @implementation MyCustomClass
- -(void)launchTaskWithData:(id)data
- {
- //創(chuàng)建一個(gè)NSInvocationOperation對(duì)象,并初始化到方法;
- //在這里,selector參數(shù)后的值是你想在另外一個(gè)線程中運(yùn)行的方法(函數(shù),Method);
- //在這里,object后的值是想傳遞給前面方法的數(shù)據(jù)
- NSInvocationOperation *theOp = [[NSInvocationOperation alloc]initWithTarget:self selector:@selector(myTashMethod:) object:data];
- //下面將我們建立的操作"Operation"加入到本地程序的共享的隊(duì)列中(加入后方法就會(huì)立刻被執(zhí)行)
- //更多的時(shí)候是由我們自己建立“操作”隊(duì)列
- [[MyAppDelegate sharedOperationQueue] addOperation:theOp];
- }
- //這個(gè)是真正運(yùn)行在另外一個(gè)線程的“方法”
- - (void)myTaskMethod:(id)data
- {
- // Perform the task.
- }
- @end
- //一個(gè)NSOperationQueue 操作隊(duì)列,就相當(dāng)于一個(gè)線程管理器,而非一個(gè)線程。因?yàn)槟憧梢栽O(shè)置這個(gè)線程管理器內(nèi)可以并行運(yùn)行的的線程數(shù)量等等。
- //下面是建立并初始化一個(gè)操作隊(duì)列:
- @interface MyViewController : UIViewController {
- NSOperationQueue* operationQueue;
- //在頭文件中聲明該隊(duì)列
- }
- @end
- @implementation MyViewController
- -(id)init
- {
- self = [super init];
- if (self) {
- //初始化操作隊(duì)列
- operationQueue = [[NSOperationQueue alloc] init];
- [operationQueue setMaxConcurrentOperationCount:1];
- //在這里限定了該隊(duì)列只同時(shí)運(yùn)行一個(gè)線程
- //這個(gè)隊(duì)列已經(jīng)可以使用了
- }
- return self;
- }
- - (void)dealloc
- {
- [operationQueue release];
- [super dealloc];
- }
- @end
- //簡(jiǎn)單介紹之后,其實(shí)可以發(fā)現(xiàn)這種方法是非常簡(jiǎn)單的。很多的時(shí)候我們使用多線程僅僅是為了防止主線程堵塞,而NSInvocationOperation就是最簡(jiǎn)單的多線程編程,在iPhone編程中是經(jīng)常被用到的。
- /////////////////////////////////////////////////////////////
- //在主線程里加入一個(gè)loading畫(huà)面……
- {
- [window addSubview:view_loading];
- //另一個(gè)新的線程,可能需要時(shí)間進(jìn)行后臺(tái)處理,為了防止主程序在這段時(shí)間靜止等待,將后臺(tái)處理放在主線程之外的線程執(zhí)行,執(zhí)行完以后,通知主線程更新數(shù)據(jù)。
- [NSThread detachNewThreadSelector:@selector:(init_backup:) toTarget:self withObject:nil];
- }
- //可以通過(guò)performSelectorOhMainThread更新UI元素,比如設(shè)置進(jìn)度條等等。***消除loading畫(huà)面,載入主View。
- -(void)init_backup:(id)sender
- {
- NSAutorelease* pool = [[NSAutoreleasePool alloc] init];
- //新建的線程需要一個(gè)自動(dòng)釋放池對(duì)線程中申請(qǐng)的內(nèi)存進(jìn)行管理
- 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的多線程實(shí)現(xiàn)和線程同步
從接口的定義中可以知道,NSThread和大多數(shù)iphone的接口對(duì)象一樣,有兩種方式可以初始化:
一種使用initWithTarget :(id)target selector:(SEL)selector object:(id)argument,但需要負(fù)責(zé)在對(duì)象的retain count為0時(shí)調(diào)用對(duì)象的release方法清理對(duì)象。
另一種則使用所謂的convenient method,這個(gè)方便接口就是detachNewThreadSelector,這個(gè)方法可以直接生成一個(gè)線程并啟動(dòng)它,而且無(wú)需為線程的清理負(fù)責(zé)。
- #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;
- // 鎖對(duì)象
- 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āng)前票數(shù)是:%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