不管是iphone中还是其他的操作系统,多线程在各种编程语言中都是难点,很多语言中实现起来很麻烦,objective-c虽然源于c,但其多线程编程却相当简单,可以与java相媲美。多线程编程是防止主线程堵塞,增加运行效率等等的最佳方法。而原始的多线程方法存在很多的毛病,包括线程锁死等。
一、线程创建与启动
线程创建主要有二种方式:
(id)init; // designated initializer
(id)initWithTarget:(id)target selector:
(SEL)selector object:(id)argument;
当然,还有一种比较特殊,就是使用所谓的convenient method,这个方法可以直接生成一个线程并启动它,而且无需为线程的清理负责。这个方法的接口是:
(void)detachNewThreadSelector:
(SEL)aSelector toTarget:
(id)aTarget withObject:
(id)anArgument
前两种方法创建后,需要手机启动,启动的方法是:
(void)start;
二、线程的同步与锁
要说明线程的同步与锁,最好的例子可能就是多个窗口同时售票的售票系统了。我们知道在java中,使用synchronized来同步,而iphone虽然没有提供类似java下的synchronized关键字,但提供了NSCondition对象接口。查看NSCondition的接口说明可以看出,NSCondition是iphone下的锁对象,所以我们可以使用NSCondition实现iphone中的线程安全。这是来源于网上的一个例子:
SellTicketsAppDelegate.h 文件
// SellTicketsAppDelegate.h
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 文件
// 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
三、线程的交互
线程在运行过程中,可能需要与其它线程进行通信,如在主线程中修改界面等等,可以使用如下接口:
(void)performSelectorOnMainThread:
(SEL)aSelector withObject:
(id)arg waitUntilDone:
(BOOL)wait
由于在本过程中,可能需要释放一些资源,则需要使用NSAutoreleasePool来进行管理,如:
(void)startTheBackgroundJob {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
// to do something in your thread job
...
[self performSelectorOnMainThread:@selector(makeMyProgressBarMoving) withObject:nil waitUntilDone:NO];
[pool release];
}
举例说明怎么简单的创建一个子线程。
用到的类是NSThread类,这里使用detachNewTheadSelector:toTagaet:withObject创建一个线程。
函数setupThread:(NSArray*)userInfor。通过userInfor将需要的数据传到线程中。
函数定义:
[代码]c#/cpp/oc代码:
01
-(void)setupThread:(NSArray*)userInfor{
02
03
[NSThread
detachNewThreadSelector:@selector(threadFunc:) toTarget:self withObject:(id)userInfor];
04
05
}
06
07
-
(void)threadFunc:(id)userInfor{
08
09
NSAutoreleasePool*pool
= [[NSAutoreleasePool alloc] init];
10
11
//。。。。需要做的处理。
12
13
//这里线程结束后立即返回
14
15
[self
performSelectorOnMainThread:@selector(endThread) withObject:nil waitUntilDone:NO];
16
17
[pool
release];
18
19
}
performSelectorOnMainThread通知主线程执行函数endThread。也可以使用performSelector:onThread:withObject:waitUntil 通知某线程执行线程结束后的处理。
线程内不要刷新界面。如果需要刷新界面,通过performSelectorOnMainThread,调出主线程中的方法去刷新。
例如,启动一个线程下载图片:
//启动线程
[NSThread detachNewThreadSelector:@selector(downloadImage:) toTarget:self withObject:url];
//线程函数
[代码]c#/cpp/oc代码:
01
-
(void)
downloadImage:(NSString*)url{
02
03
_subThreed
= [NSThread currentThread];
04
05
self.uploadPool
= [[NSAutoreleasePool alloc] init];
06
self.characterBuffer
= [NSMutableData data];
07
done
= NO;
08
[[NSURLCache
sharedURLCache] removeAllCachedResponses];
09
10
NSMutableURLRequest
*theRequest = [NSMutableURLRequest requestWithURL:[NSURLURLWithString:url]];
11
12
self.connection
= [[NSURLConnection alloc] initWithRequest:theRequest delegate:self];
13
[self
performSelectorOnMainThread:@selector(httpConnectStart) withObject:nil waitUntilDone:NO];
14
if (connection
!= nil) {
15
do {
16
[[NSRunLoop
currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
17
} while (!done);
18
}
19
20
self.photo
= [UIImage imageWithData:characterBuffer];
21
22
23
//下载结束,刷新
24
[self
performSelectorOnMainThread:@selector(fillPhoto) withObject:nil waitUntilDone:NO];
25
26
//
Release resources used only in this thread.
27
self.connection
= nil;
28
[uploadPool
release];
29
self.uploadPool
= nil;
30
31
_subThreed
= nil;
32
}
33
34
35
36
#pragma
mark NSURLConnection Delegate methods
37
38
/*
39
Disable
caching so that each time we run this app we are starting with a clean slate. You may not want to do this in your application.
40
*/
41
-
(NSCachedURLResponse *)connection:(NSURLConnection *)connection willCacheResponse:(NSCachedURLResponse *)cachedResponse {
42
43
return nil;
44
}
45
46
//
Forward errors to the delegate.
47
-
(void)connection:(NSURLConnection
*)connection didFailWithError:(NSError *)error {
48
done
= YES;
49
[self
performSelectorOnMainThread:@selector(httpConnectEnd) withObject:nil waitUntilDone:NO];
50
[characterBuffer
setLength:0];
51
52
}
53
54
//
Called when a chunk of data has been downloaded.
55
-
(void)connection:(NSURLConnection
*)connection didReceiveData:(NSData *)data {
56
//
Process the downloaded chunk of data.
57
58
[characterBuffer
appendData:data];
59
60
}
61
62
-
(void)connectionDidFinishLoading:(NSURLConnection
*)connection {
63
64
[self
performSelectorOnMainThread:@selector(httpConnectEnd) withObject:nil waitUntilDone:NO];
65
//
Set the condition which ends the run loop.
66
done
= YES;
67
68
}
首先我们需要创建一个线程有两种方法:
- (id)initWithTarget:(id)target selector:(SEL)selector object:(id)argument
+ (void)detachNewThreadSelector:(SEL)aSelector toTarget:(id)aTarget withObject:(id)anArgument
因为第二种方法不用对线程进行清理,所以我们常用第二种哦个方法。
[NSThread detachNewThreadSelector:@selector(new:) toTarget:self withObject:nil];
- (void)new:(id)sender{
[_myCondition lock];
//performSelectorInBackgroud主要进行逻辑上处理
[self performSelectorInBackgroud:@selector(doInBackgroud:) withObject:nil];
//perfomSelectorOnMainThread主要进行界面UI上的处理
[self perfomSelectorOnMainThread:@selector(doOnMain:) withObject:nil];
//[NSThread sleepForTimeInterval:n];
[_myCondition signal];
[_myCondition unlock];
[NSThread exit];
return;
}
iphone 线程总结— detachNewThreadSelector的使用
最新推荐文章于 2018-09-19 10:54:53 发布