以下是開發初期收集整理的一點資料,簡單實用,希望對新人有協助,都是網路上收集的,原始出處以不明,若侵犯您的權益,請告知,本人將及時刪除相關內容。
多線程之NSInvocationOperation
多線程編程是防止主線程堵塞,增加運行效率等等的最佳方法。而原始的多線程方法存在很多的毛病,包括線程鎖死等。在Cocoa中,Apple提供了NSOperation這個類,提供了一個優秀的多線程編程方法。
本次介紹NSOperation的子集,簡易方法的NSInvocationOperation:
@implementation MyCustomClass
- (void)launchTaskWithData:(id)data
{
//建立一個NSInvocationOperation對象,並初始化到方法
//在這裡,selector參數後的值是你想在另外一個線程中啟動並執行方法(函數,Method)
//在這裡,object後的值是想傳遞給前面方法的資料
NSInvocationOperation* theOp = [[NSInvocationOperation alloc] initWithTarget:self
selector:@selector(myTaskMethod:) 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];
//正如Alan經常說的,我們是程式的好公民,需要釋放記憶體!
[super dealloc];
}
@end簡單介紹之後,其實可以發現這種方法是非常簡單的。很多的時候我們使用多線程僅僅是為了防止主線程堵塞,而NSInvocationOperation就是最簡單的多線程編程,在iPhone編程中是經常被用到的。
///////////////////////////////////////////////////////////////////////////////////////////////////
1 在主線程裡加入一個loading畫面……
2 {
3 [window addSubview:view_loading];
4 [NSThread detachNewThreadSelector:@selector(init_backup:) toTarget:self withObject:nil];
5 }
可以通過performSelectorOhMainThread更新UI元素,比如設定進度條等等。最後消除loading畫面,載入主View。
7 - (void)init_backup:(id)sender
8 {
9 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
10
11 // ...
12 int i = status;
13 [self performSelectorOnMainThread:@selector(show_loading:) withObject:[NSNumber numberWithInt:i] waitUntil Done:NO];
14
15 [view_loading removeFromSuperview];
16 [window addSubview:tabcontroller_main.view];
17 [pool release];
18 }
///////////////////////////////////////////////////////
利用iphone的多線程實現和線程同步
從介面的定義中可以知道,NSThread和大多數iphone的介面對象一樣,有兩種方式可以初始化:
一種使用initWithTargetid)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
// SellTickets
//
// Created by sun dfsun2009 on 09-11-10.
// Copyright __MyCompanyName__ 2009. All rights reserved.
//
#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
-------------------------------------------------------------------------------------
// 定義
#import <UIKit/UIKit.h>
@interface ThreadSyncSampleViewController : UIViewController {
int _threadCount;
NSCondition *_myCondition;
}
@end
//實現檔案如下:
#import "ThreadSyncSampleViewController.h"
@implementation ThreadSyncSampleViewController
/*
// The designated initializer. Override to perform setup that is required before the view is loaded.
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
if (self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]) {
// Custom initialization
}
return self;
}
*/
/*
// Implement loadView to create a view hierarchy programmatically, without using a nib.
- (void)loadView {
}
*/
// Implement viewDidLoad to do additional setup after loading the view, typically from a nib.
- (void)viewDidLoad {
[super viewDidLoad];
//
//_myCondition = nil;
//
_myCondition = [[NSCondition alloc] init];
//
NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:30
target:self
selector:@selector(threadTester)
userInfo:nil
repeats:YES];
[timer fire];
}
- (void)threadTester{
[_myCondition lock];
_threadCount = -2;
//如果有n個要等待的thread,這裡置成-n
[_myCondition unlock];
//
NSLog(@"");
NSLog(@"------------------------------------------------------------------------------");
[NSThread detachNewThreadSelector:@selector(threadOne) toTarget:self withObject:nil];
[NSThread detachNewThreadSelector:@selector(threadTwo) toTarget:self withObject:nil];
[NSThread detachNewThreadSelector:@selector(threadThree) toTarget:self withObject:nil];
return;
}
- (void)threadOne{
NSLog(@"@@@ In thread 111111 start.");
[_myCondition lock];
int n = rand()%5 + 1;
NSLog(@"@@@ Thread 111111 Will sleep %d seconds ,now _threadCount is : %d",n,_threadCount);
sleep(n);
//[NSThread sleepForTimeInterval:n];
_threadCount ++ ;
NSLog(@"@@@ Thread 111111 has sleep %d seconds ,now _threadCount is : %d",n,_threadCount);
[_myCondition signal];
NSLog(@"@@@ Thread 1111111 has signaled ,now _threadCount is : %d",_threadCount);
[_myCondition unlock];
NSLog(@"@@@ In thread one complete.");
[NSThread exit];
return;
}
- (void)threadTwo{
NSLog(@"### In thread 2222222 start.");
[_myCondition lock];
int n = rand()%5 + 1;
NSLog(@"### Thread 2222222 Will sleep %d seconds ,now _threadCount is : %d",n,_threadCount);
sleep(n);
// [NSThread sleepForTimeInterval:n];
_threadCount ++ ;
NSLog(@"### Thread 2222222 has sleep %d seconds ,now _threadCount is : %d",n,_threadCount);
[_myCondition signal];
NSLog(@"### Thread 2222222 has signaled ,now _threadCount is : %d",_threadCount);
[_myCondition unlock];
//_threadCount ++ ;
NSLog(@"### In thread 2222222 complete.");
[NSThread exit];
return;
}
- (void)threadThree{
NSLog(@"<<< In thread 333333 start.");
[_myCondition lock];
while (_threadCount < 0) {
[_myCondition wait];
}
NSLog(@"<<< In thread 333333 ,_threadCount now is %d ,will start work.",_threadCount);
[_myCondition unlock];
NSLog(@"<<< In thread 333333 complete.");
[NSThread exit];
return;
}
/*
// Override to allow orientations other than the default portrait orientation.
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
// Return YES for supported orientations
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
*/
- (void)didReceiveMemoryWarning {
// Releases the view if it doesn't have a superview.
[super didReceiveMemoryWarning];
// Release any cached data, images, etc that aren't in use.
}
- (void)viewDidUnload {
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
}
- (void)dealloc {
[_myCondition release];
[super dealloc];
}
@end