1、使用NSThread开辟新线程
使用NSThread的类方法:[NSThread detachNewThreadSelector: @selector(myNewThreadMethod:) toTarget: someObject wothObject: object]
则会调用方法[someObject myNewThreadMethod:]方法
2、主线程与后台之间的通信
使用NSObject的performSelectorOnMainThread: withObject: waitUntilDone:方法执行主线程中的方法
3、应用使用了多个线程,但有时需要确保两个线程不会使用同一代码块,否则应用可能产生冲突,导致用户产生混乱或者文件被多次访问,
解决方法:(1)使用NSLock让其他线程等待,直到当前线程处理完关键代码块为止,然后下一个线程再完成它的动作。比如按一下按钮,进度条从0到100,连续按两次按钮,进度条从0到100后,再变为0到100,而不是中断。
首先,将NSLock对象作为属性添加到视图控制器中; @property(strong) NSLock *threadLock;
@synthesize threadLock;
然后,实例化NSLock对象; self.threadLock = [[NSLock alloc] init];
最后,在需要锁定的代码块前,添加[self.threadLock lock]; 在可以释放的地方,添加[self,threadLock unlock];
例如:
-void bigTask
{
[self.threadLock lock];
for(int i = 0;i <40000;i++){
NSString *newStr = [NSString stringWithFormat:@"i=%i",i];
NSLog(@"%@",newStr);
}
[self.threadLock unlock];
}
解决办法(2)使用@synchronized锁定线程
想要保证在同一时刻只有一个线程会使用某个代码块,可将整个代码块放在以@synchronized指令开头的花括号中。
-void bigTask
{
@synchronized(self){
for(int i = 0;i <40000;i++){
NSString *newStr = [NSString stringWithFormat:@"i=%i",i];
NSLog(@"%@",newStr);
}
}
}
@synchronized指令完成的多线程行为,比如按一下按钮,进度条从0到100,连续按两次按钮,进度条从0到100后,再变为0到100,而不是中断。这与NSLock有何区别? 有待查找答案。。。。
其他异步方法:
4、使用Grand Central Dispatch(GCD)进行异步处理
GCD在OSX10.6与iOS4中被引入进来。GCD需要使用名为”块“的编程技术,块是可看做对象的代码区域,这意味着可以在花括号之间放置代码行,然后将它们看做对象。
通常情况下,块被用作方法的参数。
GCD使用块而不是方法(带有@selector指令),这意味着无须将希望执行的代码都放到新方法中。相反,需要从调用GCD函数的函数中将代码作为参数传递给GCD函数,
使用GCD函数dispatch_async可以完成任务,比如:
-(void)bigTaskAction
{
[self.myActivityIndicator startAnimating];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0),^{
int updateUIWhen = 1000;
for(int i = 0;i<10000,i++)
{
NSLog(@"i = %@",i);
if(i == updateUIWhen){
float f = (float)i/10000;
NSNumber *percentDone = [NSNumber numberWithFloat:f];
dispatch_sync(dispatch_get_main_queue(),^{
[self.progressView setProgress:[percentDone floatValue] animated:YES];
});
updateUIWhen += 1000;
}
}
dispatch_sync(dispatch_get_main_queue(),^{
[self.progressView setProgress:1.0 animated:YES];
self.myActivityIndicator stopAnimating];
});
});
}
看GCD函数:<span style="background-color: rgb(255, 255, 153);">dispatch_async</span>(<span style="background-color: rgb(102, 255, 255);">dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0</span><span style="color:#33ccff;">)</span>,<span style="background-color: rgb(204, 51, 204);">^{}</span>);
第一部分是函数名dispatch_async,这是个会异步执行的GCD函数,另外有名为<span style="font-family: Arial, Helvetica, sans-serif;">dispatch_sync的类似函数会同步执行代码;</span>
<span style="font-family: Arial, Helvetica, sans-serif;">函数的第一个参数是分发队列:</span><span style="background-color: rgb(255, 255, 255); font-family: Arial, Helvetica, sans-serif;">dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0) 这个</span><pre name="code" class="objc"><span style="background-color: rgb(255, 255, 255); font-family: Arial, Helvetica, sans-serif;">dispatch_get_global_queue函数会一次返回该应用默认的分发队列。</span>
<span style="background-color: rgb(255, 255, 255); font-family: Arial, Helvetica, sans-serif;">注意:GCD支持名为代码队列的概念,队列会被调度以在下一个可用的处理器上执行。在使用GCD时,需要指定将代码放在哪个队列中。这里使用的是默认队列,默认队列也可以用于后台处理,还可以使用主队列,主队列类似于用户界面的主线程。</span>
对于GCD分发队列来说,在使用dispatch_async时无法确定代码块的执行顺序,系统会选择最高效的方式。因此,如果顺序很重要,可以使用dispacth_sync。
5、在GCD中使用顺序队列
使用GCD进行异步处理的时候,要求块每次都按照它们在代码中出现的顺序执行,可以使用GCD顺序队列加载代码块,
这些代码块会按照它们在队列中的顺序执行。可以通过GCD函数dispatch_queue_create(DISPATCH_QUEUE_SERIAL,0)来创建顺序队列。
确保顺序队列位于所服务对象的生命周期范围内。
首先,创建顺序队列属性: @property(assign) dispatch_queue_t serialQueue; @synthesize serialQueue;
在viewDidLoad中 self.serialQueue = dispatch_queue_create<span style="font-family: Arial, Helvetica, sans-serif;">(DISPATCH_QUEUE_SERIAL,0);</span><pre name="code" class="objc">使用时,
-(void)bigTaskAction
{
dispatch_async(self.serialQueue,^{
dispatch_sync(dispatch_get_main_queue(),^{
[self.myActivityIndicator startAnimating];
});
<pre name="code" class="objc"> int updateUIWhen = 1000;
for(int i = 0;i<10000,i++)
{
NSLog(@"i = %@",i);
if(i == updateUIWhen){
float f = (float)i/10000;
NSNumber *percentDone = [NSNumber numberWithFloat:f];
dispatch_sync(dispatch_get_main_queue(),^{
[self.progressView setProgress:[percentDone floatValue] animated:YES];
});
updateUIWhen += 1000;
}
}
dispatch_sync(dispatch_get_main_queue(),^{
[self.progressView setProgress:1.0 animated:YES];
self.myActivityIndicator stopAnimating];
});
});
}
6、使用NSOperationQueue实现异步处理
NSOperationQueue表示待执行的代码队列。可以通过NSOperationQueue在后台运行代码或是在主队列中运行以响应用户界面动作。
NSOperationQueue可以通过多种方式来添加代码。如果操作系统支持块,则可以通过addOperationWithBlock:方法直接向队列中添加代码,
否则,需要将待执行的代码放在NSOperation子类中。
例如使用块:
首先,添加局部实例: NSOperationQueue *serialQueue; NSOperationQueue * mainQueue;
在viewDidLoad中实例化它们: mainQueue = [NSOperationQueue mainQueue];
serialQueue = [[NSOperationQueue alloc] init];
serialQuaue.maxConcurrentOperationCount = 1;
-(void)bigTaskAction
{
[serialQueue addOperationWithBlock:^{
[mainQueue addOperationWithBlock:^{
[self.myActivityIndicator startAnimating];
}];
int updateUIWhen = 1000;
for(int i = 0;i<10000,i++)
{
NSLog(@"i = %@",i);
if(i == updateUIWhen){
float f = (float)i/10000;
NSNumber *percentDone = [NSNumber numberWithFloat:f];
[mainQueue addOperationWithBlock:^{
[self.progressView setProgress:[percentDone floatValue] animated:YES];
}];
updateUIWhen += 1000;
}
}
[mainQueue addOperationWithBlock:^{
[self.progressView setProgress:1.0 animated:YES];
self.myActivityIndicator stopAnimating];
}];
}];
}