0Pricing
Objective-C iOS Development for Legacy & Enterprise Apps · レッスン

複雑なタスクのためのNSOperationQueue

NSOperationとNSOperationQueueを使って、依存関係を含む並行タスクの実行をより構造的かつ管理しやすくします。

「複雑なタスクのためのNSOperationQueue」はCoddyKit上の無料Objective-C iOS Development for Legacy & Enterprise Appsレッスンです。 これはレッスン3/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはObjective-C iOS Development for Legacy & Enterprise Apps学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 Objective-C iOS Development for Legacy & Enterprise Appsコースには全4レッスンが含まれています。

このレッスンの一部はまだ翻訳されておらず、英語で表示されています。

Why NSOperationQueue?

You've learned about Grand Central Dispatch (GCD) for concurrent tasks. While powerful, GCD can become complex for intricate task management.

NSOperationQueue offers a higher-level, object-oriented way to handle concurrency. It builds on top of GCD, providing more control and features like dependencies, cancellation, and state management.

What is NSOperation?

At the core of NSOperationQueue is NSOperation. It's an abstract class representing a single unit of work that can be executed concurrently.

You don't instantiate NSOperation directly. Instead, you use its concrete subclasses or create your own custom subclasses to define specific tasks.

  • Encapsulates work: Each operation is a self-contained task.
  • Manages state: Operations have states like "ready," "executing," "finished."
  • Supports dependencies: Operations can depend on others completing first.

Build Your Own Operation

To create a custom operation, you subclass NSOperation and override its main method. This is where your task's logic goes.

Remember to mark your operation as "finished" when done, especially for asynchronous operations. For synchronous operations, main handles it.

Try running this simple custom operation:

#import <Foundation/Foundation.h>

// CustomOperation.h
@interface CustomOperation : NSOperation
@end

// CustomOperation.m
@implementation CustomOperation
- (void)main {
  if (self.isCancelled) {
    return; // Always check for cancellation
  }
  NSLog(@"Custom operation started!");
  // Simulate some work
  [NSThread sleepForTimeInterval:1.0];
  NSLog(@"Custom operation finished!");
}
@end

int main(int argc, const char * argv[]) {
  @autoreleasepool {
    CustomOperation *op = [[CustomOperation alloc] init];
    [op start]; // Manually start for demo
  }
  return 0;
}

Simple Tasks with BlockOperation

For simpler tasks that don't require a custom subclass, NSBlockOperation is perfect. It allows you to wrap one or more blocks of code as an operation.

This is often used for quick, one-off tasks without the overhead of creating a new class.

Here's how to use it:

#import <Foundation/Foundation.h>

int main(int argc, const char * argv[]) {
  @autoreleasepool {
    NSBlockOperation *blockOp = [NSBlockOperation blockOperationWithBlock:^{
      NSLog(@"Block operation running!");
      [NSThread sleepForTimeInterval:0.5];
      NSLog(@"Block operation done!");
    }];
    [blockOp start]; // Manually start for demo
  }
  return 0;
}

Executing with NSOperationQueue

To truly leverage concurrency, you add operations to an NSOperationQueue. The queue manages the execution of operations, often concurrently.

The queue decides when to start operations based on their readiness and dependencies. It handles the threading for you.

Observe how both operations run concurrently:

#import <Foundation/Foundation.h>

@interface CustomOperation : NSOperation
@end

@implementation CustomOperation
- (void)main {
  if (self.isCancelled) return;
  NSLog(@"Custom operation started!");
  [NSThread sleepForTimeInterval:1.0];
  NSLog(@"Custom operation finished!");
}
@end

int main(int argc, const char * argv[]) {
  @autoreleasepool {
    NSOperationQueue *queue = [[NSOperationQueue alloc] init];

    CustomOperation *op1 = [[CustomOperation alloc] init];
    NSBlockOperation *op2 = [NSBlockOperation blockOperationWithBlock:^{
      NSLog(@"Block operation started!");
      [NSThread sleepForTimeInterval:0.5];
      NSLog(@"Block operation finished!");
    }];

    [queue addOperation:op1];
    [queue addOperation:op2];

    // Wait for all operations to complete
    [queue waitUntilAllOperationsAreFinished];
    NSLog(@"All operations completed!");
  }
  return 0;
}

Chaining Tasks with Dependencies

One of NSOperation's most powerful features is setting dependencies. An operation can be configured to only start after another specific operation (or set of operations) has finished.

This is crucial for tasks that must be executed in a particular order, ensuring data consistency or proper workflow.

Notice how "Op B" waits for "Op A":

#import <Foundation/Foundation.h>

int main(int argc, const char * argv[]) {
  @autoreleasepool {
    NSOperationQueue *queue = [[NSOperationQueue alloc] init];

    NSBlockOperation *opA = [NSBlockOperation blockOperationWithBlock:^{
      NSLog(@"Operation A running...");
      [NSThread sleepForTimeInterval:1.0];
      NSLog(@"Operation A done!");
    }];

    NSBlockOperation *opB = [NSBlockOperation blockOperationWithBlock:^{
      NSLog(@"Operation B running...");
      [NSThread sleepForTimeInterval:0.5];
      NSLog(@"Operation B done!");
    }];

    // Op B depends on Op A
    [opB addDependency:opA];

    [queue addOperation:opA];
    [queue addOperation:opB];

    [queue waitUntilAllOperationsAreFinished];
    NSLog(@"All dependent operations completed!");
  }
  return 0;
}

Stopping Tasks Gracefully

Operations can be cancelled, which is vital for user-initiated stops or when a task becomes irrelevant.

When an operation is cancelled, its isCancelled property becomes YES. Your main method (or block) should regularly check this property and exit gracefully if it's true.

An operation that has already started might still complete some work before checking isCancelled.

#import <Foundation/Foundation.h>

@interface CancellableOperation : NSOperation
@end

@implementation CancellableOperation
- (void)main {
  for (int i = 0; i < 5; i++) {
    if (self.isCancelled) {
      NSLog(@"Operation was cancelled early!");
      return;
    }
    NSLog(@"Working... %d", i);
    [NSThread sleepForTimeInterval:0.2];
  }
  NSLog(@"Operation finished normally.");
}
@end

int main(int argc, const char * argv[]) {
  @autoreleasepool {
    NSOperationQueue *queue = [[NSOperationQueue alloc] init];
    CancellableOperation *op = [[CancellableOperation alloc] init];

    [queue addOperation:op];

    // Wait a short time then try to cancel
    [NSThread sleepForTimeInterval:0.3];
    [op cancel];
    NSLog(@"Attempted to cancel operation.");

    [queue waitUntilAllOperationsAreFinished];
    NSLog(@"Queue finished.");
  }
  return 0;
}

Post-Execution Actions

Sometimes you need to perform an action only after an operation has finished, regardless of whether it succeeded or was cancelled.

Every NSOperation has a completionBlock property. This block is executed on an arbitrary thread once the operation's main method (or blocks for NSBlockOperation) has completed.

Use it for cleanup or to update the UI (remember to dispatch UI updates to the main thread!).

#import <Foundation/Foundation.h>

int main(int argc, const char * argv[]) {
  @autoreleasepool {
    NSOperationQueue *queue = [[NSOperationQueue alloc] init];

    NSBlockOperation *op = [NSBlockOperation blockOperationWithBlock:^{
      NSLog(@"Operation running...");
      [NSThread sleepForTimeInterval:0.5];
    }];

    op.completionBlock = ^{
      NSLog(@"Operation completion block executed!");
      // If updating UI, dispatch to main thread:
      // dispatch_async(dispatch_get_main_queue(), ^{ /* UI update */ });
    };

    [queue addOperation:op];
    [queue waitUntilAllOperationsAreFinished];
    NSLog(@"All done!");
  }
  return 0;
}

Managing Parallelism

An NSOperationQueue can execute multiple operations concurrently. You can control this behavior using the maxConcurrentOperationCount property.

  • 1: Operations run serially (one at a time).
  • NSOperationQueueDefaultMaxConcurrentOperationCount (usually -1): The queue decides the optimal number based on system conditions.
  • Any positive integer: Limits the number of operations running simultaneously.

This helps prevent resource exhaustion and manage workload.

Check Your Understanding

Test your knowledge on NSOperation and NSOperationQueue.

NSOperationQueue Recap

Great job! You've explored NSOperation and NSOperationQueue.

  • NSOperation represents a single unit of work.
  • NSOperationQueue manages the execution of operations, providing a higher-level abstraction over GCD.
  • Key features include dependencies, cancellation, completion blocks, and control over concurrency.
  • Use NSBlockOperation for simple tasks and custom subclasses for complex, reusable operations.

This powerful framework helps you build robust and manageable concurrent applications.

よくある質問

「複雑なタスクのためのNSOperationQueue」レッスンは無料ですか?

はい。「複雑なタスクのためのNSOperationQueue」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、Objective-C iOS Development for Legacy & Enterprise Appsコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 Objective-C iOS Development for Legacy & Enterprise Appsコースには全4レッスンが含まれています。

「複雑なタスクのためのNSOperationQueue」で何を学びますか?

NSOperationとNSOperationQueueを使って、依存関係を含む並行タスクの実行をより構造的かつ管理しやすくします。 ブラウザで直接実行するハンズオンコードでObjective-C iOS Development for Legacy & Enterprise Appsを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。

Objective-C iOS Development for Legacy & Enterprise Appsを始めるのに経験は必要ですか?

事前経験は必要ありません。CoddyKitのObjective-C iOS Development for Legacy & Enterprise Appsは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン3/4です。

「複雑なタスクのためのNSOperationQueue」レッスンにはどのくらい時間がかかりますか?

ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。

このObjective-C iOS Development for Legacy & Enterprise Appsレッスンでコードを書いて実行できますか?

はい。すべてのObjective-C iOS Development for Legacy & Enterprise Appsレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。

このコースのすべてのレッスン

  1. API呼び出しのためのNSURLSession
  2. Grand Central Dispatch(GCD)
  3. 複雑なタスクのためのNSOperationQueue
  4. NSJSONSerializationによるJSONのパース
← Objective-C iOS Development for Legacy & Enterprise Appsに戻る