- 浏览: 42576 次
- 性别:
- 来自: 上海
最新评论
-
chengt:
http://jareye.com/
推荐一个下载jar包的网站-----jareye.com -
chengt:
http://jareye.com/
推荐一个下载jar包的网站-----jareye.com
多线程的使用与注意事项
这一回,主要介绍一下iPhone SDK中多线程的使用方法以及注意事项。虽然现在大部分PC应用程序都支持多线程/多任务的开发方式,但是在iPhone上,Apple并不推荐使用多线程的编程方式。但是多线程编程毕竟是发展的趋势,而且据说即将推出的iPhone OS4将全面支持多线程的处理方式。所以说掌握多线程的编程方式,在某些场合一定能挖掘出iPhone的更大潜力。
从例子入手
先从一个例程入手,具体的代码参考了这里。还有例程可以下载。
多线程程序的控制模型可以参考这里,一般情况下都是使用 管理者/工人模型, 这里,我们使用iPhone SDK中的 NSThread 来实现它。
首先创建一个新的 View-based application 工程,名字为 "TutorialProject" 。界面如下图所示,使用UILabel实现两部分的Part(Thread Part和Test Part),Thread Part中包含一个UIProgressView和一个UIButton;而Test Part包含一个值和一个UISlider。
接下来,在 TutorialProjectViewController.h 文件中创建各个UI控件的 IBOutlets.
同时,也需要创建outlets变量的property.
接下来定义按钮按下时的动作函数,以及slider的变化函数。
然后在 TutorialProjectViewController.m 文件中synthesize outlets,并在文件为实现dealloc释放资源。
现在开始线程部分的代码,首先当 thread button 被按下的时候,创建新的线程.
该按钮被按下后,隐藏按钮以禁止多次创建线程。然后初始化显示值和进度条,最后创建新的线程,线程的函数为 startTheBackgroundJob.
具体的 startTheBackgroundJob 函数定义如下.
在第1行,创建了一个 NSAutoreleasePool 对象,用来管理线程中自动释放的对象资源。这里 NSAutoreleasePool 在线程退出的时候释放。这符合 Cocoa GUI 应用程序的一般规则。
最后一行,阻塞调用(waitUntilDone状态是ON)函数 makeMyProgressBarMoving。
这里计算用于显示的进度条的值,利用 NSTimer ,每0.5秒自增0.01,当值等于1的时候,进度条为100%,退出函数并显示刚才被隐藏的按钮。
最后,添加 UISlider 的实现函数,用来更改主线程中 Test Part 中的 label 值
编译执行,按下线程开始按钮,你将看到进度条的计算是在后台运行。
使用线程的注意事项
线程的堆栈大小iPhone设备上的应用程序开发也是属于嵌入式设备的开发,同样需要注意嵌入式设备开发时的几点问题,比如资源上限,处理器速度等。
iPhone 中的线程应用并不是无节制的,官方给出的资料显示iPhone OS下的主线程的堆栈大小是1M,第二个线程开始都是512KB。并且该值不能通过编译器开关或线程API函数来更改。
你可以用下面的例子测试你的设备,这里使用POSIX Thread(pthread),设备环境是 iPhone 3GS(16GB)、SDK是3.1.3。
结果如下:
模拟器
Main thread: base:0xc0000000 / size:524288
rlimit-> soft:8388608 / hard:67104768
Thread: base:0xb014b000 / size:524288
设备
Main thread: base:0x30000000 / size:524288
rlimit-> soft:1044480 / hard:1044480
Thread: base:0xf1000 / size:524288
由此可见,当你测试多线程的程序时,模拟器和实际设备的堆栈大小是不一样的。如果有大量递归函数调用可要注意了。
Autorelease
如果你什么都不考虑,在线程函数内调用 autorelease 、那么会出现下面的错误:
一般,在线程中使用内存的模式是,线程最初
而在线程结束的时候 [pool drain] 或 [pool release]。<sup><a class="footref" name="fnr.1" href="#fn.1">1.</a></sup>
子线程中描画窗口
多线程编程中普遍遵循一个原则,就是一切与UI相关的操作都有主线程做,子线程只负责事务,数据方面的处理。那么如果想在子线程中更新UI时怎么做呢?如果是在windows下,你会 PostMessage 一个描画更新的消息,在iPhone中,需要使用performSelectorOnMainThread 委托主线程处理。
比如,如果在子线程中想让 UIImageView 的 image 更新,如果直接在线程中
这么做,什么也不会出现的。需要将该处理委托给主线程来做,像下面:
就OK了
<a class="footnum" name="fn.1" href="#fnr.1">1.</a> drain 与 release 的区别前提是你的系统中是否有GC,如果有,-drain 需要送一个消息给GC (objc_collect_if_needed),而如果没有GC,drain = release
这一回,主要介绍一下iPhone SDK中多线程的使用方法以及注意事项。虽然现在大部分PC应用程序都支持多线程/多任务的开发方式,但是在iPhone上,Apple并不推荐使用多线程的编程方式。但是多线程编程毕竟是发展的趋势,而且据说即将推出的iPhone OS4将全面支持多线程的处理方式。所以说掌握多线程的编程方式,在某些场合一定能挖掘出iPhone的更大潜力。
从例子入手
先从一个例程入手,具体的代码参考了这里。还有例程可以下载。
多线程程序的控制模型可以参考这里,一般情况下都是使用 管理者/工人模型, 这里,我们使用iPhone SDK中的 NSThread 来实现它。
首先创建一个新的 View-based application 工程,名字为 "TutorialProject" 。界面如下图所示,使用UILabel实现两部分的Part(Thread Part和Test Part),Thread Part中包含一个UIProgressView和一个UIButton;而Test Part包含一个值和一个UISlider。
接下来,在 TutorialProjectViewController.h 文件中创建各个UI控件的 IBOutlets.
@interface TutorialProjectViewController : UIViewController { // ------ Tutorial code starts here ------ // Thread part IBOutlet UILabel *threadValueLabel; IBOutlet UIProgressView *threadProgressView; IBOutlet UIButton *threadStartButton; // Test part IBOutlet UILabel *testValueLabel; // ------ Tutorial code ends here ------ }
同时,也需要创建outlets变量的property.
@property (nonatomic, retain) IBOutlet UILabel *threadValueLabel; @property (nonatomic, retain) IBOutlet UIProgressView *threadProgressView; @property (nonatomic, retain) IBOutlet UIProgressView *threadStartButton; @property (nonatomic, retain) IBOutlet UILabel *testValueLabel;
接下来定义按钮按下时的动作函数,以及slider的变化函数。
- (IBAction) startThreadButtonPressed:(UIButton *)sender; - (IBAction) testValueSliderChanged:(UISlider *)sender;
然后在 TutorialProjectViewController.m 文件中synthesize outlets,并在文件为实现dealloc释放资源。
@synthesize threadValueLabel, threadProgressView, testValueLabel, threadStartButton; ... - (void)dealloc { // ------ Tutorial code starts here ------ [threadValueLabel release]; [threadProgressView release]; [threadStartButton release]; [testValueLabel release]; // ------ Tutorial code ends here ------ [super dealloc]; }
现在开始线程部分的代码,首先当 thread button 被按下的时候,创建新的线程.
- (IBAction) startThreadButtonPressed:(UIButton *)sender { threadStartButton.hidden = YES; threadValueLabel.text = @"0"; threadProgressView.progress = 0.0; [NSThread detachNewThreadSelector:@selector(startTheBackgroundJob) toTarget:self withObject:nil]; }
该按钮被按下后,隐藏按钮以禁止多次创建线程。然后初始化显示值和进度条,最后创建新的线程,线程的函数为 startTheBackgroundJob.
具体的 startTheBackgroundJob 函数定义如下.
- (void)startTheBackgroundJob { NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; // 线程开始后先暂停3秒(这里只是演示暂停的方法,你不是必须这么做的) [NSThread sleepForTimeInterval:3]; [self performSelectorOnMainThread:@selector(makeMyProgressBarMoving) withObject:nil waitUntilDone:NO]; [pool release]; }
在第1行,创建了一个 NSAutoreleasePool 对象,用来管理线程中自动释放的对象资源。这里 NSAutoreleasePool 在线程退出的时候释放。这符合 Cocoa GUI 应用程序的一般规则。
最后一行,阻塞调用(waitUntilDone状态是ON)函数 makeMyProgressBarMoving。
- (void)makeMyProgressBarMoving { float actual = [threadProgressView progress]; threadValueLabel.text = [NSString stringWithFormat:@"%.2f", actual]; if (actual < 1) { threadProgressView.progress = actual + 0.01; [NSTimer scheduledTimerWithTimeInterval:0.5 target:self selector:@selector(makeMyProgressBarMoving) userInfo:nil repeats:NO]; } else threadStartButton.hidden = NO; }
这里计算用于显示的进度条的值,利用 NSTimer ,每0.5秒自增0.01,当值等于1的时候,进度条为100%,退出函数并显示刚才被隐藏的按钮。
最后,添加 UISlider 的实现函数,用来更改主线程中 Test Part 中的 label 值
- (IBAction) testValueSliderChanged:(UISlider *)sender { testValueLabel.text = [NSString stringWithFormat:@"%.2f", sender.value]; }
编译执行,按下线程开始按钮,你将看到进度条的计算是在后台运行。
使用线程的注意事项
线程的堆栈大小iPhone设备上的应用程序开发也是属于嵌入式设备的开发,同样需要注意嵌入式设备开发时的几点问题,比如资源上限,处理器速度等。
iPhone 中的线程应用并不是无节制的,官方给出的资料显示iPhone OS下的主线程的堆栈大小是1M,第二个线程开始都是512KB。并且该值不能通过编译器开关或线程API函数来更改。
你可以用下面的例子测试你的设备,这里使用POSIX Thread(pthread),设备环境是 iPhone 3GS(16GB)、SDK是3.1.3。
#include "pthread.h" void *threadFunc(void *arg) { void* stack_base = pthread_get_stackaddr_np(pthread_self()); size_t stack_size = pthread_get_stacksize_np(pthread_self()); NSLog(@"Thread: base:%p / size:%u", stack_base, stack_size); return NULL; } - (void)applicationDidFinishLaunching:(UIApplication *)application { void* stack_base = pthread_get_stackaddr_np(pthread_self()); size_t stack_size = pthread_get_stacksize_np(pthread_self()); struct rlimit limit; getrlimit(RLIMIT_STACK, &limit); NSLog(@"Main thread: base:%p / size:%u", stack_base, stack_size); NSLog(@" rlimit-> soft:%llu / hard:%llu", limit.rlim_cur, limit.rlim_max); pthread_t thread; pthread_create(&thread, NULL, threadFunc, NULL); // Override point for customization after app launch [window addSubview:viewController.view]; [window makeKeyAndVisible]; }
结果如下:
模拟器
Main thread: base:0xc0000000 / size:524288
rlimit-> soft:8388608 / hard:67104768
Thread: base:0xb014b000 / size:524288
设备
Main thread: base:0x30000000 / size:524288
rlimit-> soft:1044480 / hard:1044480
Thread: base:0xf1000 / size:524288
由此可见,当你测试多线程的程序时,模拟器和实际设备的堆栈大小是不一样的。如果有大量递归函数调用可要注意了。
Autorelease
如果你什么都不考虑,在线程函数内调用 autorelease 、那么会出现下面的错误:
NSAutoReleaseNoPool(): Object 0x********* of class NSConreteData autoreleased with no pool in place ….
一般,在线程中使用内存的模式是,线程最初
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc]init];
而在线程结束的时候 [pool drain] 或 [pool release]。<sup><a class="footref" name="fnr.1" href="#fn.1">1.</a></sup>
子线程中描画窗口
多线程编程中普遍遵循一个原则,就是一切与UI相关的操作都有主线程做,子线程只负责事务,数据方面的处理。那么如果想在子线程中更新UI时怎么做呢?如果是在windows下,你会 PostMessage 一个描画更新的消息,在iPhone中,需要使用performSelectorOnMainThread 委托主线程处理。
比如,如果在子线程中想让 UIImageView 的 image 更新,如果直接在线程中
imageView.image = [UIImage imageNamed:@"Hoge.png"];
这么做,什么也不会出现的。需要将该处理委托给主线程来做,像下面:
[delegate performSelectorOnMainThread:@selector(theProcess:) withObject:nil waitUntilDone:YES];
就OK了
<a class="footnum" name="fn.1" href="#fnr.1">1.</a> drain 与 release 的区别前提是你的系统中是否有GC,如果有,-drain 需要送一个消息给GC (objc_collect_if_needed),而如果没有GC,drain = release
发表评论
-
iOS开发中如何解决TableView中图片延时加载
2012-06-01 13:44 1546IOS开发中如何解决TableView中图片延时加载是本文要介 ... -
让模拟器也支持GPS定位(模拟实现)
2012-06-01 13:36 2087iOS上的GPS定位一般需要真机才能看到效果,但在开发的过程中 ... -
判断UITextField的输入只为数字的方法
2012-06-01 13:35 1088实现下面的委托 #define NUMBERS @" ... -
反向地理编码用法
2012-06-01 13:33 1095与地图打交道时,有时需要查找经纬度获取地理信息,MapKit提 ... -
关于出现僵尸信号SIGBAT或者EXC_BAD_ACCESS的解决方案
2012-06-01 13:31 575随着用xcode开发的深入,相信很多同学都对出现SIGBAT或 ... -
iOS 应用的 UI 开发资源
2012-05-28 23:27 859中文 http://blog.csdn.net/column ... -
汉字转拼音
2012-05-20 19:47 914// // ChineseToPinyin.h // ... -
修改图标上的提示符(badge)
2012-05-20 19:35 902程序推送,或者AppStore软件有更新都会有提示,那代码怎么 ... -
Info.plist中常用的key简介
2012-05-20 19:10 852UIRequiresPersistentWiFi 在程序中弹出 ... -
返回 父级 的父级 view
2012-05-09 14:48 830[color=blue]有3个view A,B,C A是第一级 ... -
如何获取view的controller
2012-05-09 14:45 1437[b]如何获取view的controller[/b] ... -
xcode4 svn+ssh
2012-05-04 22:18 10931. Clear the contents of your ~ ... -
在程序中使用GPS定位
2012-03-17 10:28 809这一回简单地介绍一下G ... -
开源ZXing在XCode上如何使用
2012-03-17 10:18 9221.在 zxing/iphone/ZXingWidget/里的 ... -
iphone 二维码 使用说明
2012-03-17 10:16 1075转自:http://blog.csdn.net/linkai5 ... -
iphone开发随笔,有用的
2012-03-14 20:52 7111.将view设置成圆角 首先导入QuartzCore.fra ... -
iphone开发中发送短信
2012-03-14 20:46 1288iOS4.0新加入了MFMessageComposeViewC ... -
iphone中设置控件语言
2012-03-14 20:40 841最近项目遇到这样一个问题: 发送短信时,发现控件显示的是英 ... -
How to use ZXing(decode qr code) .
2012-03-14 20:26 1225ZXing for iOS is a sub-project ... -
SVN+SSH
2012-03-10 20:00 1066Setup SSH access Go to the cPan ...
相关推荐
总结C++中多线程要注意的事项,不能跨线程调用MFC对象等等
MFC多线程编程注意事项,很不错的资料。
多线程调用DBUS服务注意事项 多线程调用DBUS服务注意事项 多线程调用DBUS服务注意事项 多线程调用DBUS服务注意事项
第十一节 多线程的使用与注意事项.docx
主要给大家介绍了关于JAVA多线程的使用场景与注意事项的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者使用java具有一定的参考学习价值,需要的朋友们下面来一起学习学习吧
批量爬虫下载时,单线程下载文件有时慢有时快。...同时附上单线程下载(带进度条显示功能)代码,单线程下载(带进度条显示)和多线程代码的时间比较,实测多线程能有效提升下载效率,效果还是比较不错的。
描述了c++的多线程的注意事项。包括不能跨线程访问MFC对象等
书中以muduo网络库为例,讲解这种编程模型的使用方法及注意事项。 《Linux多线程服务端编程:使用muduo C++网络库》的宗旨是贵精不贵多。掌握两种基本的同步原语就可以满足各种多线程同步的功能需求,还能写出更...
spring boot 通过任务执行器 taskexecutor 来实现多线程和并发编程。下面这篇文章主要给大家介绍了关于spring boot中多线程开发的注意事项,文中通过示例代码介绍的非常详细,需要的朋友可以参考下
本书以muduo 网络库为例,讲解这种编程模型的使用方法及注意事项。 本书的宗旨是贵精不贵多。掌握两种基本的同步原语就可以满足各种多线程同步的功能需求,还能写出更易用的同步设施。掌握一种进程间通信方式和一种...
线程的创建,使用、多线程的使用注意事项。
本书主要讲述采用现代C++在x86-64 Linux上编写多线程TCP网络服 务程序的主流常规技术, 这也是我对过去5年编写生产环境下的多线程 服务端程序的经验总结。 本书重点讲解多线程...解这种编程模型的使用方法及注意事项
《Linux多线程服务端编程:使用muduo C++网络库》主要讲述采用现代C++在x86-64 Linux上编写多线程TCP网络服务程序的主流常规技术,重点讲解一种适应性较强的多线程服务器的编程模型,即one loop per thread。...
Linux下多线程及多进程及同步与互斥编程详细介绍
Java 与C# 是现扣今网络开发的两大主要平台,而多线程编程则是进行并行处理计算中的基础,本文主要阐述了在Java 与C#开发平台下如何进行多线程编程的方法及注意事项,并且比较和分析两种开发平台下进行多线程编程的...
详细介绍了java多线程的原理以及常用多线程编程方法及注意事项。
这时使用多线程,A线程去加载文件夹下的文件,B线程实现过滤拷贝的工作. 在大型静态生成的项目里体现更突出. 注意事项:备份完成后打包步骤需要安装压缩包运行软件,否则将打包失败. 所以需要先安装压缩包,安装文件为...
多线程日志工具源码 项目描述 运行环境: .NET Framework 4.0 可打开源码降级至.NET Framework 2.0 或者 .NET...注意事项: *主要文件为Log.cs *扩展log文件名可以根据需求定制来自51ASP 欢迎感兴趣的用户下载学习。
本书以 muduo 网络库为例,讲解这种编程模型的使用方法及注意事项。 本书的宗旨是贵精不贵多。掌握两种基本的同步原语就可以满足各种多线程同步的功能需求,还能写出更易用的同步设施。掌握一种进程间通信方式和一种...