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; }
相关文章推荐
- Python爬虫学习笔记——豆瓣登陆(一)
- 【Objective-C学习记录】第二十八天
- coreApp="true";android:sharedUserId="android.uid.system";android:process="system"
- [Err] 1062 - Duplicate entry '111' for key 'PRIMARY'
- android基础学习之BroadcastReceiver
- 拍照、相册裁剪
- android-Allowing Other Apps to Start Your Activity(App之间进行交互)
- 获取桌面应用、动态壁纸、输入法应用
- 拍照、相册裁剪
- 《Monkey Android》第1课之前言
- Kaggle Titanic Competition-第二部分
- App内访问的网络必须使用HTTPS协议
- Unity引擎编译后的程序是如何运行在iOS和Android上
- VIJOS-P1153 猫狗大战 dp 贪心
- 微信公众号开发之接入
- spring,mybatis整合时出现的一个小问题
- 万年历的算法
- 支付宝sdk接入问题点
- 数制总结
- 20.(转)Android的样式(Style)和主题(Theme)