iphone 线程总结— detachNewThreadSelector的使用

不管是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;

}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值