您的位置:首页 > 其它

iphone 线程总结— detachNewThreadSelector的使用

2015-12-29 20:07 537 查看
不管是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;

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: