重庆分公司,新征程启航
为企业提供网站建设、域名注册、服务器等服务
如何编写多线程应用
创新互联公司长期为成百上千客户提供的网站建设服务,团队从业经验10年,关注不同地域、不同群体,并针对不同对象提供差异化的产品和服务;打造开放共赢平台,与合作伙伴共同营造健康的互联网生态环境。为门源企业提供专业的成都网站建设、网站制作,门源网站改版等技术服务。拥有十多年丰富建站经验和众多成功案例,为您定制开发。
现在你已经知道一个好的多线程应用是怎样的,它是如何帮助你解决问题的,那么如何编写一个好的多线程应用呢?我会向你介绍iPhone应用中编写和处理多线程应用的主要技术。
创建一个线程
为了创建一个线程,你可以使用下面的方法:
NSThread
POSIX Threads
NSObject 来创建一个新的线程
NSOperation和NSOperationQueue
我会逐一介绍他们,然后会举一些例子,因为他们都有各自的优点和缺点。在本部分结束的时候,我会给出一个表格来进行对比,是得你能够分清他们的不同,这样在你的需求中就能够选择一个正确的方案。
NSThread
用NSThread创建一个新的线程,你可以简单的调用:
[NSThread detachNewThreadSelector:@selector(threadMethod:) toTarget:self
withObject:nil];
这个方法会在你的应用中创建一个新的detached线程。一个detached线程就是它的所有资源会被系统回收,当线程存在的时候。
有些属性你需要知道。
+(void)detachNewThreadSelector:(SEL)aSelector toTarget:(id)aTarget withObject:(id)anArgument
aSelector:当线程开始的时候,这个方法会在目标对象中被调用。根据苹果的文档,这个selector只有一个参数,没有返回值。
aTarget:将要执行在aSelector参数中所指定的方法的对象。
anArgument:唯一的一个参数;当线程开始的时候,它会被传递到aSelector方法中。
如果你想创建一个线程,但是不想启动它,你可以使用下面的机制:
NSThread* myThread = [[NSThread alloc]initWithTarget:self
selector:@selector(myThreadMainMethod:)object:nil];
[myThread start]; // Actually create the thread
你可以看到,第一行,你创建了一个新的线程,然后,根据你的选择,你可以在对象上调用start来启动一个新的线程。这是非常有用的,如果你只想传递myThread对象,而不想传递selector,target和argument的话。
另一个比较好的做法是,使用NSThread对象发送一个消息给线程对象
-(void)performSelector:(SEL)aSelector onThread:(NSThread *)thrwithObject:(id)arg waitUntilDone:(BOOL)wait
这个方法会在另一个线程上queue selector。当系统自动运行线程时,线程会dequeue这个消息,然后会调用aSelector变量指定的方法。
使用POSIX线程
这个在iPhone应用中主要是用c编程时会用到。在第9章,我会更深入的讨论c编程,并能够帮助你在很多情况下提升你的iPhone apps的性能。所以这个部分可能不会帮助你太多,如果你还不了解c编程的话。如果你已经了解了c编程,Listing 6-3 展示了代码,后面会有一个解释。
Listing 6–3.POSIX Thread#include
#include
void* ThreadMethod(void* data){
// Your main logic comes here.
return NULL;
}
void LaunchThread(){
// Create the thread using POSIX routines.
pthread_attr_t attr;
pthread_t posixThreadID;
int returnVal;
// init and check if init a new thread successful
returnVal = pthread_attr_init(&attr);
assert(!returnVal);
// set attribute detach state for new thread
returnVal = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
assert(!returnVal);
// create and run the new thread
int threadError = pthread_create(&posixThreadID, &attr, &ThreadMethod, NULL);
returnVal = pthread_attr_destroy(&attr);
assert(!returnVal);
if (threadError != 0)
{
// Report an error.
}
}
NSObject
所有的对象都可以创建和detach一个新的线程来执行这些对象的selectors。你可以使用下面的这行代码在后台线程中运行doSomething方法:
[myObj performSelectorInBackground:@selector(doSomething) withObject:nil];
调用这个方法的效果和下面的这行代码是一样的:
[NSThread detachNewThreadSelector:@selector(doSomething) toTarget:myObj withObject:nil]
这个方法是比较好的,对于detach和创建一个运行后台任务的线程来说。
NSOperationQueue
NSOperationQueue是管理和运行并发任务的一个机制。NSOperationQueue的一个好处是它能够限制系统内部并发operations的数量,通过给定一个限制使得系统加载在一个可以接受的范围水平。因为这个最大线程数量的限制,如果有更多的线程实例,NSOperationQueue不会导致更多的并发线程同时在系统中运行。
你可以在queue中添加operations,但是不能删除。然而,你可以在queue中取消所有已经存在的和还没有运行的operations。表格 6-2 展示了当使用NSOperationQueue时,一些非常有用的方法。
你可以用3个不同的类来使用NSOperationQueue。
NSInvocationOperation:如果你已经有一个对象和一个方法加入到一个并发线程中,这只是一个简单的包裹。它不需要子类,所以通过这个类来创建一个简单的NSOperation对象。NSInvocationOperation是NSOperation的子类。
NSBlockOperation:这是另一包裹类,用来执行一个或多个blocks,而不需要创建一个单独的NSOperation对象来执行每一个block。当执行超过一个block时,只有所有内部的blocks都执行完毕,那么NSBlockOperation才被认为结束了。
Custom NSOperation:NSOperation是一个基类。通过继承它,你能够完全的控制整个NSOperation对象的实现,包括你的operation执行说的默认行为和报告它的状态。
使用NSOperationQueue进行多线程设计,你需要用这3个方法中的一个来创建指定的对象,然后把新创建的NSOperation加入到你的queue中。然后这个queue会为你维护和运行这些operations。
这里有一个简单的代码来帮助你创建一个NSOperationQueue,然后把相互独立的operation对象放进去,来创建一个多线程环境:
NSOperationQueue* myOperationQueue = [[NSOperationQueue alloc] init];
[myOperationQueue addOperation:myOperation]; // Add a single operation
[myOperationQueue addOperations:arrayOfOperations waitUntilFinished:NO]; // Add multipleoperations
[aQueue addOperationWithBlock:^{
/* Do Something. */
}];