iphone 线程总结— detachNewThreadSelector的使用

不管是iphone中还是其他的操作系统,多线程在各种编程语言中都是难点,很多语言中实现起来很麻烦,objective-c虽然源于c,但其多线程编程却相当简单,可以与java相媲美。多线程编程是防止主线程堵塞,增加运行效率等等的最佳方法。而原始的多线程方法存在很多的毛病,包括线程锁死等。

一、线程创建与启动

线程创建主要有二种方式:

  
  
  1. (id)init; // designated initializer  
  2. (id)initWithTarget:(id)target selector:  
  3. (SEL)selector object:(id)argument; 

当然,还有一种比较特殊,就是使用所谓的convenient method,这个方法可以直接生成一个线程并启动它,而且无需为线程的清理负责。这个方法的接口是:

  
  
  1. (void)detachNewThreadSelector:  
  2. (SEL)aSelector toTarget:  
  3. (id)aTarget withObject:  
  4. (id)anArgument 

前两种方法创建后,需要手机启动,启动的方法是:

  
  
  1. (void)start; 

二、线程的同步与锁

要说明线程的同步与锁,最好的例子可能就是多个窗口同时售票的售票系统了。我们知道在java中,使用synchronized来同步,而iphone虽然没有提供类似java下的synchronized关键字,但提供了NSCondition对象接口。查看NSCondition的接口说明可以看出,NSCondition是iphone下的锁对象,所以我们可以使用NSCondition实现iphone中的线程安全。这是来源于网上的一个例子:

SellTicketsAppDelegate.h 文件

  
  
  1. // SellTicketsAppDelegate.h  
  2. import <UIKit/UIKit.h> 
  3. @interface SellTicketsAppDelegate : NSObject <UIApplicationDelegate> {  
  4.      int tickets;  
  5.      int count;  
  6.      NSThread* ticketsThreadone;  
  7.      NSThread* ticketsThreadtwo;  
  8.      NSCondition* ticketsCondition;  
  9.      UIWindow *window;  
  10. }  
  11. @property (nonatomic, retain) IBOutlet UIWindow *window;  
  12. @end  
  13. SellTicketsAppDelegate.m 文件  
  14. // SellTicketsAppDelegate.m  
  15. import "SellTicketsAppDelegate.h"  
  16. @implementation SellTicketsAppDelegate  
  17. @synthesize window;  
  18. - (void)applicationDidFinishLaunching:(UIApplication *)application {  
  19.      tickets = 100;  
  20.      count = 0;  
  21.      // 锁对象  
  22.      ticketCondition = [[NSCondition alloc] init];  
  23.      ticketsThreadone = [[NSThread alloc] initWithTarget:self selector:@selector(run) object:nil];  
  24.      [ticketsThreadone setName:@"Thread-1"];  
  25.      [ticketsThreadone start];  
  26.      ticketsThreadtwo = [[NSThread alloc] initWithTarget:self selector:@selector(run) object:nil];  
  27.      [ticketsThreadtwo setName:@"Thread-2"];  
  28.      [ticketsThreadtwo start];  
  29.      //[NSThread detachNewThreadSelector:@selector(run) toTarget:self withObject:nil];  
  30.       // Override point for customization after application launch  
  31.      [window makeKeyAndVisible];  
  32.  
  33. }  
  34.  
  35. - (void)run{  
  36.      while (TRUE) {  
  37.      // 上锁  
  38.          [ticketsCondition lock];  
  39.          if(tickets > 0){  
  40.              [NSThread sleepForTimeInterval:0.5];  
  41.              count = 100 - tickets;  
  42.              NSLog(@"当前票数是:%d,售出:%d,线程名:%@",tickets,count,[[NSThread currentThread] name]);  
  43.              tickets--;  
  44.          }else{  
  45.              break;  
  46.          }  
  47.          [ticketsCondition unlock];  
  48.      }  
  49. }  
  50. - (void)dealloc {  
  51. [ticketsThreadone release];  
  52.      [ticketsThreadtwo release];  
  53.      [ticketsCondition release];   
  54.      [window release];  
  55.      [super dealloc];  
  56. }  
  57. @end 

三、线程的交互

线程在运行过程中,可能需要与其它线程进行通信,如在主线程中修改界面等等,可以使用如下接口:

  
  
  1. (void)performSelectorOnMainThread:  
  2. (SEL)aSelector withObject:  
  3. (id)arg waitUntilDone:  
  4. (BOOL)wait 

由于在本过程中,可能需要释放一些资源,则需要使用NSAutoreleasePool来进行管理,如:

  
  
  1. (void)startTheBackgroundJob {       
  2. NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];  
  3.     // to do something in your thread job  
  4.     ...  
  5.     [self performSelectorOnMainThread:@selector(makeMyProgressBarMoving) withObject:nil waitUntilDone:NO];  
  6.     [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;

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值