如何立即cancel当前正在运行的nsoperationqueue

(有码)NSOperation
(有码)NSOperation
NSOperation(队列是任务的载体)
//创建操作(单独创建操作要调用start)
&&& NSOperation *invocation = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(downloadImage) object:nil];
//开始操作(不添加到队列,是在主线程运行)
&& [invocation start];
//将操作放到队列中,不需要start(自动异步执行)
&&& NSOperationQueue *queque = [[NSOperationQueue alloc] init];
&&& [queque addOperation:invocation];
//把多个操作放到队列
&&& [queque addOperation:invocation];
&&& [queque addOperation:invocation];
&&& [queque addOperation:invocation];
注意:队列中的操作只能添加一次,文章中重复添加是为了简化代码,不要模仿
//GCD中并发队列使用最多,所以NSOpration把GCD里面的并发队列封装起来
//NSOprationQueue队列本质就是GCD里面的并发队列
//操作就是GCD异步执行的任务
//block放到队列
&&& NSOperation *block = [NSBlockOperation blockOperationWithBlock:^{
&&&&&&& NSLog(@&%@&,[NSThread currentThread]);
&&& //把操作放到队列
&&& [queue addOperation:block];
&&& [queue addOperation:block];
&&& [queue addOperation:block];
//快速调用方法
[queue addOperationWithBlock:^{
&&&&&&& NSLog(@&111&);
//在block里面还可以添加block(异步执行,不是在block之后才开始)
NSBlockOperation *block = [NSBlockOperation blockOperationWithBlock:^{
&&&&&&& NSLog(@&%@&,[NSThread currentThread]);
&&& [block addExecutionBlock:^{
&&&&&&& NSLog(@&%@&, [NSThread currentThread]);
//快速创建队列更新UI(重要)
- (void)connectWithThread{
&&& NSOperationQueue *queue = [[NSOperationQueue alloc] init];
&&& [queue addOperationWithBlock:^{
&&&&&&& NSLog(@&耗时操作&);
&&&&&&& [[NSOperationQueue mainQueue] addOperationWithBlock:^{
&&&&&&&&&&& NSLog(@&更新UI&);
&&&&&&& }];
只要是NSOpration的子类都能添加到操作队列
一旦添加就会异步执行
没有添加,要调用start方法,在当前线程通讯
如果要做线程间通信,可以使用[NSOpration mainQueue]拿到主队列,往主队列添加操作(更新UI)
//设置最大并发数(不是线程的数量,而是同时执行任务的数量,执行完任务的线程不一定马上执行下一任务,要放到线程池)
self.queue.maxConcurrentOperationCount = 2;
//让队列挂起
self.queue.suspended = YES;
//确定操作是否为0
self.queue.operationCount == 0
//取消队列所有操作(不会改变队列的挂起状态),一般,取消后会(删除所有任务)设置挂起状态,以便于队列的继续
&&& [self.queue cancelAllOperations];
//添加依赖关系,等待上面操作结束
&&&[op2 addDependency:op1];
NSOperation和GCD的区别
&& &将任务(block)添加到队列(串行/并行(全局)),指定任务的方法(同步/异步)
&& &拿到dispatch_get_main_queue()线程间通讯
&& &NSOpration无法做到,一次性执行,,延迟执行,调度组
NSOpration:
&& &将操作(异步执行)添加到队列(并发/全局)
&& &[NSOprationQueue mainQueue]任务添加到主队列,就会在主线程执行
&& &提供了一些GCD不好实现的,最大并发数
&& &暂停,继续——挂起
&& &取消所有任务
&& &依赖关系
GCD是基于c的底层api,NSOperation属于object-c类。iOS首先引入的是NSOperation,IOS4之后引入了GCD和NSOperationQueue并且其内部是用gcd实现的。
相对于GCD:
1,NSOperation拥有更多的函数可用,具体查看api。
2,在NSOperationQueue中,可以建立各个NSOperation之间的依赖关系。
3,有kvo,可以监测operation是否正在执行(isExecuted)、是否结束(isFinished),是否取消(isCanceld)。
4,NSOperationQueue可以方便的管理并发、NSOperation之间的优先级。
GCD主要与block结合使用。代码简洁高效。
& GCD也可以实现复杂的多线程应用,主要是建立个个线程时间的依赖关系这类的情况,但是需要自己实现相比NSOperation要复杂。
具体使用哪个,依需求而定。&从个人使用的感觉来看,比较合适的用法是:除了依赖关系尽量使用GCD,因为苹果专门为GCD做了性能上面的优化。
GCD仅仅支持FIFO队列,而NSOperationQueue中的队列可以被重新设置优先级,从而实现不同操作的执行顺序调整。
GCD不支持异步操作之间的依赖关系设置。如果某个操作的依赖另一个操作的数据(生产者-消费者模型是其中之一),使用NSOperationQueue能够按照正确的顺序执行操作。GCD则没有内建的依赖关系支持。
NSOperationQueue支持KVO,意味着我们可以观察任务的执行状态。
了解以上不同,我们可以从以下角度来定义原则
GCD更接近底层,而NSOperationQueue则更高级抽象,所以GCD在追求性能的底层操作来说,是速度最快的。这取决于使用Instruments进行代码性能分析,如有必要的话
2. 从异步操作之间的事务性,顺序行,依赖关系。GCD需要自己写更多的代码来实现,而NSOperationQueue已经内建了这些支持
3. 如果异步操作的过程需要更多的被交互和UI呈现出来,NSOperationQueue会是一个更好的选择。底层代码中,任务之间不太互相依赖,而需要更高的并发能力,GCD则更有优势
我的热门文章
即使是一小步也想与你分享问题:苹果公司现任CEO是谁?2字正确答案:库克
主题 : 如何立即cancel当前正在运行的NSOperation
级别: 骑士
可可豆: 1626 CB
威望: 1626 点
在线时间: 198(时)
发自: Web Page
如何立即cancel当前正在运行的NSOperation&&&
假设一个操作NSOperation *theOp添加到NSOperationQueue *queue中去,并且开始运行,如何立即取消这个操作呢?[queue cancelAllOperations];和[theOp cancel];都不能立即取消啊好像,有什么办法吗?[queue cancelAllOperations];的作用好像是让那些还没运行的NSOperation被取消,正在运行的NSOperation就没办法了。[theOp cancel];的作用好像是在这个操作没执行之前会被取消,正在执行也不起作用。
级别: 侠客
可可豆: 435 CB
威望: 335 点
在线时间: 279(时)
发自: Web Page
自己添加一个isStop属性,运行的时候,通过设置这个属性来判断是否立即停止。
级别: 侠客
UID: 82221
可可豆: 850 CB
威望: 771 点
在线时间: 199(时)
发自: Web Page
你的main函数中需要提供出口 可以将你的任务分段,类似。虽然我也觉得比较土,但是还不知道有什么好方案a();if (_isCancel)b();if (_isCancel)c();
级别: 新手上路
可可豆: 6 CB
威望: 6 点
在线时间: 26(时)
发自: Web Page
cancel&& 不是只有在未执行之前 有效么 NSoperation执行了 也有效?&&
级别: 新手上路
可可豆: 6 CB
威望: 6 点
在线时间: 26(时)
发自: Web Page
我回错帖子了 不好意思
关注本帖(如果有新回复会站内信通知您)
苹果公司现任CEO是谁?2字 正确答案:库克
发帖、回帖都会得到可观的积分奖励。
按"Ctrl+Enter"直接提交
关注CocoaChina
关注微信 每日推荐
扫一扫 浏览移动版多线程 NSOperation
多线程 NSOperation
一. & &NSThread 可以实现多线程编程,但是需要我们去管理线程的生命周期,还要考虑线程同步,加锁问题。造成一些性能上的开销。我们可以配合使用NSOperation 和NSOperationQueue 实现多线程编程。
使用步骤:
& & 1.先将执行的操作封装到一个NSOperation对象中
& & 2.然后将NSOperation对象添加到NSOperationQueue中
& & 3.系统会自动将NSOperation封装的操作放到一条新线程中执行
在此过程中我们根本不需要考虑线程的生命周期,同步,加锁等问题。
比如以上微博粉丝列表,每一个头像要从新浪的服务器下载后才能显示,而且需要异步下载。这时候你就可以把每一行的图片下载操作封装到一个NSOperation对象中,上面有6行,所以要创建6个NSOperation对象,然后添加到NSOperationQueue中,分别下载不同的图片,下载完毕后,回到对应的行,将图片显示出来。
默认情况下,NSOperation并不具备封装操作的能力,必须使用它的子类,使用NSOperation子类的方法有三种:
& & (1)NSInvocationOperation
& & (2)NSBlockOperation
& & (3)自定义子类继承NSOperation,实现内部相应的方法
使用方法:
& & &(1)NSInvocationOperation
& & NSInvocationOperation *operation = [[[NSInvocationOperation
alloc]initWithTarget:self
selector:@selector(runThread:)
object:@"run"]autorelease];&
//初始化一个NSinvocationOperation对象,它是基于一个对象和selector来创建的。
& & [operation start];&
//调用start方法后并不会开一条新线程去执行操作,而是在当前线程同步执行操作.只有将operation放到一个NSOperationQueue中,才会异步执行操作.
& & &(2)NSBlockOperation&
同步执行一个操作
& & &NSBlockOperation *operation = [NSBlockOperation
blockOperationWithBlock:^() {& &&
NSLog(@"执行一个新的操作");
& & [operation
start];& //开始执行任务 & 这里还是在当前线程同步执行操作,并没有异步执行
并发执行多个操作
NSBlockOperation *operation = [NSBlockOperation
blockOperationWithBlock:^() {
NSLog(@"执行第一次操作,线程:%@",[NSThread currentThread]);
& & }];& & //初始化一个NSBlockOperation
& & [operation
addExecutionBlock:^(){
NSLog(@"又执行了一个新的操作,线程:%@",[NSThread currentThread]);
& & [operation
addExecutionBlock:^(){
NSLog(@"又执行了一个新的操作,线程:%@",[NSThread currentThread]);
& & [operation
addExecutionBlock:^(){
NSLog(@"又执行了一个新的操作,线程:%@",[NSThread currentThread]);
& & }];& & //通过addExecutionBlock:方法添加了新的操作,一共封装了4个操作
& & [operation start];&
//start之后,会在不同线程中,并发执行这4个操作
& & 结果:又执行了一个新操作,线程:&NSThread 0x7121d50&{name = (null),num = 1}
又执行了一个新操作,线程:&NSThread 0x7421ed0&{name = (null),num = 5}
执行第一次操作,线程:&NSThread 0x742de50&{name = (null),num = 3}
又执行了一个新操作,线程:&NSThread 0x7157bf0&{name = (null),num
num值不同,说明线程不同。
& &(3)NSOperation的其他用法
& & &operation开始执行之后,默认会一直执行到操作完成,我们也可以调用cancel方法中途取消操作。
& & [operation
cancel]; &//取消操作
& & 操作完成之后的操作:
& & 如果想在一个NSOperation执行完成之后做一些事情,就调用NSOperation的setCompletionBlock方法来设置想做的事情
& & &&operation.completionBlock = ^(){&
NSLog(@"执行完毕"); &//当operation封装的操作执行完毕后,就会回调执行Block的内容
& &(4)自定义NSOperation,重写main方法
& & DownloadOperation.h
#import &Foundation/Foundation.h&
@protocol DownloadOperationDelegate;
@interface DownloadOperation :
NSOperation
//图片Url路径
@property(nonatomic,copy)NSString *imageU
@property(nonatomic,assign)
id &DownloadOperationDelegate&
-(id)initWithUrl:(NSString *)url delegate:(id&DownloadOperationDelegate&)
//图片下载协议
@protocol DownloadOperationDelegate &NSObject&
-(void)downloadFinishWithImage:(UIImage *)
& &DownloadOperation.m
#import "DownloadOperation.h"
@implementation DownloadOperation
@synthesize delegate =
_delegate;
@synthesize imageUrl =
_imageUrl;
-(id)initWithUrl:(NSString *)url delegate:(id&DownloadOperationDelegate&)delegate{
if (self = [super
self.imageUrl =
self.delegate =
& & return
//释放内存
-(void)dealloc{
& & [super
& & [_imageUrl
//执行主任务
-(void)main{&
//重载了main方法,等会就把下载的图片写到这个方法中。
& & //新建一个自动释放池,如果是异步执行操作,那么将无法访问到主线程的自动释放池
& & @autoreleasepool { &
//创建的是当前线程的自动释放池
正确响应取消事件
& & 默认一个NSOperation开始执行之后,会一直执行到任务结束。
& & NSOperation &提供一个cancel方法,可以取消当前的操作。
& & 如果是自定义NSOperation的话,需要手动处理这个取消事件。比如一旦调用了cancel方法,应该马上终止main方法的执行,并及时回收一些资源。
& & 处理取消事件的具体做法是:在main中定期的调用isCancelled方法监测操作是否已经被取消,也就是说是否调用了cancel方法,如果返回YES,表示已取消,则立即让main方法返回。
& & 以下地方可能需要调用isCancelled方法:
& & & & (1)在执行任何实际的工作之前,也就是说在main方法的开头。因为取消可能发生在任何时候,甚至在operation执行之前。
& & & &(2) 执行了一段耗时的操作之后也需要监测操作是否已经被取消。
-(void)main{&
//重载了main方法,等会就把下载的图片写到这个方法中。
& & //新建一个自动释放池,如果是异步执行操作,那么将无法访问到主线程的自动释放池
& & @autoreleasepool { &
//创建的是当前线程的自动释放池
& & & & if (self.isCancelled)
//判断是否被取消,若取消了就没有必要往下执行了。
//获取图片数据
NSURL *url = [NSURL
URLWithString:self.imageUrl];
NSData *imageData = [NSData
dataWithContentsOfURL:url];
if (self.isCancelled) {
& & & & & & url =
& & & & & & imageData =
& & & & & &
//初始化图片
UIImage *image = [UIImage
imageWithData:imageData];
if (self.isCancelled) {
& & & & & & image =
& & & & & &
if ([self.delegate
respondsToSelector:@selector(downloadFinishWithImage:)]) {
& & & & & & [(NSObject *)self.delegate
performSelectorOnMainThread:@selector(downloadFinishWithImage:)
withObject:image waitUntilDone:NO]; &
//将图片数据传给delegate对象
&& & & & & &
发表评论:
TA的最新馆藏NSOperation - NSHipster
Written by
July 14th, 2014
In life, there&s always work to be done. Every day brings with it a steady stream of tasks and chores to fill the working hours of our existence.
Yet, no matter how burdened one&s personal ToDo list becomes, it pales in comparison to the workload of an iOS app, of which millions of computations are expected, all while managing to draw a frame every 16 milliseconds.
Productivity is, as in life as it is in programming, a matter of scheduling and prioritizing and multi-tasking work in order to keep up appearances.
The secret to making apps snappy is to offload as much unnecessary work to the background as possible, and in this respect, the modern Cocoa developer has two options:
and . This article will primarily focus on the latter, though it&s important to note that the two are quite complementary (more on that later).
NSOperation represents a single unit of work. It&s an abstract class that offers
a useful, thread-safe structure for modeling state, priority, dependencies, and management.
For situations where it doesn&t make sense to build out a custom NSOperation subclass, Foundation provides the concrete implementations
Examples of tasks that lend themselves well to NSOperation include , image resizing, text processing, or any other repeatable, structured, long-running task that produces associated state or data.
But simply wrapping computation into an object doesn&t do much without a little oversight. That&s where NSOperationQueue comes in:
NSOperationQueue
NSOperationQueue regulates the concurrent execution of operations. It acts as a priority queue, such that operations are executed in a roughly
manner, with higher-priority (NSOperation.queuePriority) ones getting to jump ahead of lower-priority ones. NSOperationQueue can also limit the maximum number of concurrent operations to be executed at any given moment, using the maxConcurrentOperationCount property.
NSOperationQueue itself is backed by a Grand Central Dispatch queue, though that&s a private implementation detail.
To kick off an NSOperation, either call start, or add it to an NSOperationQueue, to have it start once it reaches the front of the queue. Since so much of the benefit of NSOperation is derived from NSOperationQueue, it&s almost always preferable to add an operation to a queue rather than invoke start directly.
NSOperation encodes a rather elegant state machine to describe the execution of an operation:
ready → executing → finished
In lieu of an explicit state property, state is determined implicitly by KVO notifications on those keypaths. When an operation is ready to be executed, it sends a KVO notification for the ready keypath, whose corresponding property would then return true.
Each property must be mutually exclusive from one another in order to encode a consistent state:
ready: Returns true to indicate that the operation is ready to execute, or false if there are still unfinished initialization steps on which it is dependent.
executing: Returns true if the operation is currently working on its task, or false otherwise.
finished Returns true if the operation&s task finished execution successfully, or if the operation was cancelled. An NSOperationQueue does not dequeue an operation until finished changes to true, so it is critical to implement this correctly in subclasses to avoid deadlock.
Cancellation
It is often useful to cancel operations early to prevent needless work from being performed, whether due to a failure in a dependent operation or explicit cancellation by the user.
Similar to execution state, NSOperation communicates cancellation through KVO on the cancelled keypath. When an operation is cancelled, it should clean up any internal details and arrive in an appropriate final state as quickly as possible. Specifically, the values for both cancelled and finished need to become true, and executing needs to become false.
One thing to watch out for are the spelling peculiarities of the word &cancel&. Although spelling varies across dialects, when it comes to NSOperation:
cancel: use one L for the function (verb)
cancelled: use two L&s for the property (adjective)
All operations may not be equally important. Setting the queuePriority property will promote or defer an operation in an NSOperationQueue according to the following rankings:
NSOperationQueuePriority
public enum NSOperationQueuePriority : Int {
case VeryLow
case Normal
case VeryHigh
typedef NS_ENUM(NSInteger, NSOperationQueuePriority) {
NSOperationQueuePriorityVeryLow = -8L,
NSOperationQueuePriorityLow = -4L,
NSOperationQueuePriorityNormal = 0,
NSOperationQueuePriorityHigh = 4,
NSOperationQueuePriorityVeryHigh = 8
Quality of Service
Quality of Service is a new concept in iOS 8 & OS X Yosemite that creates consistent, high-level semantics for scheduling system resources. APIs were introduced for both
and NSOperation that use this abstraction.
For NSOperation, the threadPriority property has been deprecated in favor of this new qualityOfService property. (And good riddance—threadPriority was too unwieldy to be anything but a liability to most developers.)
Service levels establish the system-wide priority of an operation in terms of how much CPU, network, and disk resources are allocated. A higher quality of service means that more resources will be provided to perform an operation&s work more quickly.
QoS appears to use the
under the hood.
The following enumerated values are used to denote the nature and urgency of an operation. Applications are encouraged to select the most appropriate value for operations in order to ensure a great user experience:
NSQualityOfService
@available(iOS 8.0, OSX 10.10, *)
public enum NSQualityOfService : Int {
case UserInteractive
case UserInitiated
case Utility
case Background
case Default
typedef NS_ENUM(NSInteger, NSQualityOfService) {
NSQualityOfServiceUserInteractive = 0x21,
NSQualityOfServiceUserInitiated = 0x19,
NSQualityOfServiceUtility = 0x11,
NSQualityOfServiceBackground = 0x09,
NSQualityOfServiceDefault = -1
} NS_ENUM_AVAILABLE(10_10, 8_0);
.UserInteractive:UserInteractive QoS is used for work directly involved in providing an interactive UI such as processing events or drawing to the screen.
.UserInitiated: UserInitiated QoS is used for performing work that has been explicitly requested by the user and for which results must be immediately presented in order to allow for further user interaction.
For example, loading an email after a user has selected it in a message list.
.Utility: Utility QoS is used for performing work which the user is unlikely to be immediately waiting for the results.
This work may have been requested by the user or initiated automatically, does not prevent the user from further interaction, often operates at user-visible timescales and may have its progress indicated to the user by a non-modal progress indicator.
This work will run in an energy-efficient manner, in deference to higher QoS work when resources are constrained.
For example, periodic content updates or bulk file operations such as media import.
.Background: Background QoS is used for work that is not user initiated or visible.
In general, a user is unaware that this work is even happening and it will run in the most efficient manner while giving the most deference to higher QoS work.
For example, pre-fetching content, search indexing, backups, and syncing of data with external systems.
.Default: Default QoS indicates the absence of QoS information.
Whenever possible QoS information will be inferred from other sources.
If such inference is not possible, a QoS between UserInitiated and Utility will be used.
let backgroundOperation = NSOperation()
backgroundOperation.queuePriority = .Low
backgroundOperation.qualityOfService = .Background
let operationQueue = NSOperationQueue.mainQueue()
operationQueue.addOperation(backgroundOperation)
NSOperation *backgroundOperation = [[NSOperation alloc] init];
backgroundOperation.queuePriority = NSOperationQueuePriorityLow;
backgroundOperation.qualityOfService = NSOperationQualityOfServiceBackground;
[[NSOperationQueue mainQueue] addOperation:backgroundOperation];
Asynchronous Operations
Another change in iOS 8 / OS X Yosemite is the deprecation of the concurrent property in favor of the new asynchronous property.
Originally, the concurrent property was used to distinguish between operations that performed all of their work in a single main method, and those that managed their own state while executing asynchronously. This property was also used to determine whether NSOperationQueue would execute a method in a separate thread. After NSOperationQueue was changed to run on an internal dispatch queue rather than manage threads directly, this aspect of the property was ignored. The new asynchronous property clears away the semantic cobwebs of concurrent, and is now the sole determination of whether an NSOperation should execute synchronously in main, or asynchronously.
Dependencies
Depending on the complexity of an application, it may make sense to divide up large tasks into a series of composable sub-tasks. This can be done with NSOperation dependencies.
For example, to describe the process of downloading and resizing an image from a server, one might divide up networking into one operation, and resizing into another (perhaps to reuse the networking operation to download other resources, or also use the resizing operation for images already cached in memory). However, since an image can&t be resized until it&s downloaded, then the networking operation is a dependency of the resizing operation, and must be finished before the resizing operation can be started.
Expressed in code:
let networkingOperation: NSOperation = ...
let resizingOperation: NSOperation = ...
resizingOperation.addDependency(networkingOperation)
let operationQueue = NSOperationQueue.mainQueue()
operationQueue.addOperations([networkingOperation, resizingOperation], waitUntilFinished: false)
NSOperation *networkingOperation = ...
NSOperation *resizingOperation = ...
[resizingOperation addDependency:networkingOperation];
NSOperationQueue *operationQueue = [NSOperationQueue mainQueue];
[operationQueue addOperation:networkingOperation];
[operationQueue addOperation:resizingOperation];
An operation will not be started until all of its dependencies return true for finished.
Make sure not to accidentally create a dependency cycle, such that A depends on B, and B depends on A, for example. This will create deadlock and sadness.
completionBlock
When an NSOperation finishes, it will execute its completionBlock exactly once. This provides a really nice way to customize the behavior of an operation when used in a model or view controller.
let operation = NSOperation()
operation.completionBlock = {
print(&Completed&)
NSOperationQueue.mainQueue().addOperation(operation)
NSOperation *operation = ...;
operation.completionBlock = ^{
NSLog(&Completed&);
[[NSOperationQueue mainQueue] addOperation:operation];
For example, you could set a completion block on a network operation to do something with the response data from the server once it&s finished loading.
NSOperation remains an essential tool in an iOS or OS X developer&s bag of tricks. Whereas GCD is ideal for in-line asynchronous processing, NSOperation provides a more comprehensive, object-oriented model of computation for encapsulating all of the data around structured, repeatable tasks in an application.
Developers should use the highest level of abstraction possible for any given problem, and for scheduling consistent, repeated work, that abstraction is NSOperation. Other times, it makes more sense to sprinkle in some GCD (including within an NSOperation subclass implementation).
When to Use Grand Central Dispatch
Dispatch queues, groups, semaphores, sources, and barriers comprise an essential set of concurrency primitives, on top of which all of the system frameworks are built.
For one-off computation, or simply speeding up an existing method, it will often be more convenient to use a lightweight GCD dispatch than employ NSOperation.
When to Use NSOperation
NSOperation can be scheduled with a set of dependencies at a particular queue priority and quality of service. Unlike a block scheduled on a GCD queue, an NSOperation can be cancelled and have its operational state queried. And by subclassing, NSOperation can associate the result of its work on itself for future reference.
Just remember: NSOperation and Grand Central Dispatch are not mutually exclusive. Creative and effective use of both are key to developing robust and performant iOS or OS X applications.
NSMutableHipster
Questions? Corrections?
are always welcome — NSHipster is made better by readers like you.
This article uses Swift version 2.0 and was last reviewed on September 15, 2015.
Find status information for all articles on the .
Follow NSHipster
Written by
() is a writer and developer from the Rustbelt.
Next Article
XCTestCase /XCTestExpectation / measureBlock()
This week, we&ll take a look at XCTest, the testing framework built into Xcode, as well as the exciting new additions in Xcode 6: XCTestExpectation and performance tests.
Related Articles
Questions? Corrections?
is released under a .}

我要回帖

更多关于 自定义nsoperation 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信