進程是系統資源管理的最小單位。線程是程序執行的最小單位。多線程是一個進程裡包含多個線程。一個進程數據會加載到一個內存區間中,其中的線程共享相同的內存空間。各個進程的地址是獨立的,只有進程能刷新UI、更新數據。線程需要手動開啟。
建立一個簡單售票系統,連接線程的運行。首先創建一個單視圖工程,在.h文件中代碼:
@interface LinViewController : UIViewController
{
//聲明剩余票數、賣出票數成員名
int _leftTickets;
int _soldTickets;
//聲明線程成員名
NSThread * _firstThread;
NSThread * _secondThread;
NSThread * _thridThread;
//聲明線程鎖
NSCondition * _ticketsCondition;
}
//創建標簽欄的對象,用來顯示剩余票數、賣出票數、當前線程名
@property (retain, nonatomic) UILabel * leftLabel;
@property (retain, nonatomic) UILabel * soldLabel;
@property (retain, nonatomic) UILabel * currentThreadLabel;
@end在.m文件中的代碼:#import "LinViewController.h"
//預編譯變量,設置票的總數量
#define MaxTickets 100
@implementation LinViewController
//釋放創建的對象
- (void)dealloc
{
[_leftLabel release];
[_soldLabel release];
[_currentThreadLabel release];
[super dealloc];
}
- (void)viewDidLoad
{
[super viewDidLoad];
//加載輔助的標簽欄,只顯示內容
[self addLabel:nil];
//設置標簽欄對象的位置
self.leftLabel = [[UILabel alloc]initWithFrame:CGRectMake(150, 90, 100, 30)];
self.soldLabel = [[UILabel alloc]initWithFrame:CGRectMake(150, 170, 100, 30)];
self.currentThreadLabel = [[UILabel alloc]initWithFrame:CGRectMake(150, 250, 100, 30)];
//設置標簽欄對象的背景顏色
self.leftLabel.backgroundColor = [UIColor lightGrayColor];
self.soldLabel.backgroundColor = [UIColor lightGrayColor];
self.currentThreadLabel.backgroundColor = [UIColor lightGrayColor];
//把標簽欄添加到當前的視圖中
[self.view addSubview:self.leftLabel];
[self.view addSubview:self.soldLabel];
[self.view addSubview:self.currentThreadLabel];
//初始化成員並賦值
_leftTickets = MaxTickets;
_soldTickets = 0;
_ticketsCondition = [[NSCondition alloc]init];
//創建按鈕對象
UIButton * pButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
//設置按鈕的位置
[pButton setFrame:CGRectMake(80, 340, 180, 40)];
//為按鈕添加標題
[pButton setTitle:@"開始賣票" forState:UIControlStateNormal];
//設置按鈕的方法,響應方式
[pButton addTarget:self action:@selector(threadStart:) forControlEvents:UIControlEventTouchUpInside];
//把按鈕添加到當前視圖中
[self.view addSubview:pButton];
}
#pragma mark-------增加輔助標簽欄
- (void)addLabel:(id)sender
{
//初始化標簽欄對象對設置位置
UILabel * pLabel = [[UILabel alloc]initWithFrame:CGRectMake(10, 20, 300, 40)];
UILabel * pLabel1 = [[UILabel alloc]initWithFrame:CGRectMake(10, 80, 120, 50)];
UILabel * pLabel2 = [[UILabel alloc]initWithFrame:CGRectMake(10, 160, 120, 50)];
UILabel * pLabel3 = [[UILabel alloc]initWithFrame:CGRectMake(10, 240, 120, 50)];
//設置標簽欄的內容文本
pLabel.text = @"模擬火車票銷售---多線程";
pLabel1.text = @"剩余票數";
pLabel2.text = @"售出票數";
pLabel3.text = @"當前進程";
//設置標簽欄的背景顏色
pLabel.backgroundColor = [UIColor clearColor];
pLabel1.backgroundColor = [UIColor clearColor];
pLabel2.backgroundColor = [UIColor clearColor];
pLabel3.backgroundColor = [UIColor clearColor];
//設置標簽欄的文本居中
pLabel.textAlignment = NSTextAlignmentCenter;
pLabel1.textAlignment = NSTextAlignmentCenter;
pLabel2.textAlignment = NSTextAlignmentCenter;
pLabel3.textAlignment = NSTextAlignmentCenter;
//把標簽欄對象添加到視圖中
[self.view addSubview:pLabel];
[self.view addSubview:pLabel1];
[self.view addSubview:pLabel2];
[self.view addSubview:pLabel3];
//釋放創建的對象
[pLabel release];
[pLabel1 release];
[pLabel2 release];
[pLabel3 release];
}
#pragma mark-------開始賣票,線程開始運行
- (void)threadStart:(id)sender
{
//初始化子線程,設置子線程的方法
_firstThread = [[NSThread alloc]initWithTarget:self selector:@selector(sellTickets:) object:nil];
//設置子線程的名字
[_firstThread setName:@"thread-1"];
//??手動開啟子線程,必須添加,系統不能自主進行
[_firstThread start];
_secondThread = [[NSThread alloc]initWithTarget:self selector:@selector(sellTickets:) object:nil];
[_secondThread setName:@"thread-2"];
[_secondThread start];
_thridThread = [[NSThread alloc]initWithTarget:self selector:@selector(sellTickets:) object:nil];
[_thridThread setName:@"thread-3"];
[_thridThread start];
}
//賣票的方法
- (void)sellTickets:(id)sender
{
while (YES)
{
//??鎖定線程,防止同一子線程多次運行,必須有
[_ticketsCondition lock];
//判斷票是否賣完
if (_leftTickets > 0)
{
//設置線程停止0.1秒
[NSThread sleepForTimeInterval:0.1];
//賣票的算法
_leftTickets--;
_soldTickets = MaxTickets - _leftTickets;
}
else if (_leftTickets == 0)
{
NSLog(@"票已經賣完!");
break;
}
//子線程調用主線程更新視圖,只有進程能更新視圖
[self performSelectorOnMainThread:@selector(updateMyView:) withObject:[[NSThread currentThread]name] waitUntilDone:YES];
//輸出剩余票數、售出票數、當前線程,可以省略
NSLog(@"剩余票數:%i售出票數:%i當前線程%@",_leftTickets,_soldTickets,[[NSThread currentThread]name]);
//線程解鎖
[_ticketsCondition unlock];
}
}
#pragma mark-------更新界面,進程可以,線程不可以
- (void)updateMyView:(id)sender
{
//設置標簽欄的顯示內容
self.leftLabel.text = [NSString stringWithFormat:@"%i",_leftTickets];
self.soldLabel.text = [NSString stringWithFormat:@"%i",_soldTickets];
self.currentThreadLabel.text = (NSString *)sender;
//判斷是否賣完,若賣完則彈出警告框
if (_leftTickets == 0)
{
UIAlertView * pAlertView = [[UIAlertView alloc]initWithTitle:@"溫馨提示" message:@"票已經全部售出!" delegate:nil cancelButtonTitle:@"確定" otherButtonTitles:nil, nil];
[pAlertView show];
[pAlertView release];
}
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
}
@end