Four technical solutions for iOS multithreading

image

Pthread implements multi-threaded operations

Code implementation:

void * run(void *param)
{
    for (NSInteger i = 0; i < 1000; i++) {
        NSLog(@"---buttonclick---%zd---%@", i, [NSThread currentThread]);
    }

    return NULL;
}

@implementation ViewController

- (IBAction)clickButton:(id)sender {
    // Define a thread
    pthread_t thread;
    // Create a thread (parameter 1)pthread_t *restrict: pointer to the creation thread, (parameter 2)const pthread_attr_t *restrict: thread attributes (parameter 3)void *(*)(void *): pointer to functions executed by the thread, (4) the void *, restrict: null
    pthread_create(&thread, NULL, run, NULL);
    // You don't need to think about when to recycle threads
    pthread_t thread2;
    pthread_create(&thread2, NULL, run, NULL);
}Copy the code

NSThread implements multi-threading

An NSThread object represents a thread

###### Multiple ways to create threads

  1. The first way: NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(run:) object:@”jack”]; // A thread is started, but it dies when it is done. An NSThread object represents a thread [thread start];
  2. [NSThread detachNewThreadSelector:@selector(run: toTarget:self withObject:@”jack”]];
  3. The third: / / create and start threads directly [self performSelectorInBackground: @ the selector (run) withObject: @ “jack”); [NSThread sleepForTimeInterval:2.0];
#pragma mark - (void)run:(NSString *)param {// whether the current thread is the main thread for (NSInteger I = 0; i < 100; i++) { NSLog(@"---%@---%zd---%d", [NSThread currentThread], i, [NSThread isMainThread]); }}Copy the code

Method 2 and method 3: the advantages of quick way 1: the advantages of easy to get the thread to the embodiment of the communication between threads communication between threads 1 pass data to another thread 1 threads in a thread after perform specific tasks, one to the other threads continue to carry out the task communication between threads commonly used methods: small images are downloaded program

-(UIImageView *)imageView { if (! _imageView) { _imageView = [UIImageView new]; _imageView.frame = CGRectMake(0, 0, 300, 300); _imageView.center = self.view.center; [self.view addSubview:_imageView]; } return _imageView; } - (void)viewDidLoad { [super viewDidLoad]; [[NSNotificationCenter defaultCenter] addObserver:self Selector :@selector(handle_threadexit:) name:NSThreadWillExitNotification object:nil]; // Do any additional setup after loading the view. } - (void)didReceiveMemoryWarning { [super didReceiveMemoryWarning]; // Dispose of any resources that can be recreated. } -(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {// NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(run:) object:@"booob"]; // A thread is started, but it dies when it is done. An NSThread object represents a thread [thread start]; [NSThread detachNewThreadSelector:@selector(run: toTarget:self withObject:@"wang"]]; Third: / / / / create and start threads directly [self performSelectorInBackground: @ the selector (run) withObject: @ "wang000"]; [NSThread sleepForTimeInterval:2.0]; Examples / / / / get the url of the picture NSURL * url = [NSURL URLWithString: @ "https://pages.github.com/images/slideshow/yeoman.png"); NSThread *thread3 = [[NSThread alloc] initWithTarget:self Selector :@selector(downLoadWithURL:) object:url]; thread3.name = @"downloadimage..." ; [thread3 start] [thread3 start]; } #pragma mark - (void)run:(NSString *)param {// whether the current thread is the main thread for (NSInteger I = 0; i < 10; i++) { NSLog(@"---%@---%zd---%d", [NSThread currentThread], i, [NSThread isMainThread]); }} / / thread direct interaction / / download images - (void) downLoadWithURL (NSURL *) url {NSLog (@ "% @ % s, % s", a __FILE__, __FUNCTION__, [NSThread currentThread]); / / download pictures NSData * data = [NSData dataWithContentsOfURL: url]; UIImage *image = [UIImage imageWithData:data]; / / return to the main thread display images [self imageView performSelectorOnMainThread: @ the selector (setImage:) withObject: image waitUntilDone: YES]; } // handle the thread end event -(void)handle_threadexit:(NSNotification *)notify {NSThread * thread = (NSThread *)notify.object; NSLog (@ "+ + + + + + + + + + + + + + + % @ the end of the thread + + + + + + + + + + + +", thread, name); }Copy the code

Using threads is obsolete. In development, we mostly use GCD and NSOperation to implement multi-threaded operations.

— — — — — — — — — — — — — — — — — — — — —

How does THE COMMUNIST Party implement multithreading

  • GCD implements multithreading
  • The GCD introduction
  • Grand Central Dispatch is Apple’s solution to multi-core parallel computing. It automatically uses more CPU cores (e.g., dual-core, quad-core) to start threads to execute tasks. GCD automatically manages the thread life cycle (creating threads, scheduling tasks, destroying threads) without requiring us programmers to manually manage memory.

  • Tasks and Queues

  • Tasks: Perform in both synchronous and asynchronous functions
  • Queue: Used to hold tasks (concurrent serial)
images

GCD will automatically take the tasks out of the queue and put them into the corresponding thread. The task is taken out according to FIFO, which is the First in First out queue, short for First Input First Output. The tasks entered first are completed and finished before the following tasks are executed. Synchronous and asynchronous functions, concurrent queues and serial queues execute tasks synchronously: tasks can be executed immediately in the current thread, without the ability to start a thread. Asynchronous execution: Tasks can be executed when the current thread ends, with the ability to start a new thread

  • Concurrent queue: Allows multiple tasks to execute simultaneously

  • Serial queue: after the execution of one task, the next task is executed

Create concurrent/serial queue code:

- (void)viewDidLoad { [super viewDidLoad]; dispatch_queue_t queue = dispatch_get_main_queue(); Dispatch_queue_create ("searial.whenbar.com", DISPATCH_QUEUE_SERIAL); dispateserial = dispatch_queue_create("searial.whenbar.com", DISPATCH_QUEUE_SERIAL); Parameter 1:const char *label Queue name // Parameter 2:dispatch_queue_attr_t attr Queue type queueConcurrent = dispatch_queue_create("concurrent.whenbar.com", DISPATCH_QUEUE_CONCURRENT); } //1 Get the main queue -(void)runqueueMain {// Get the main queue all tasks in the main queue will be executed on the main thread. dispatch_queue_t queueMain = dispatch_get_main_queue(); } / / 2. Create a serial queue - (void) runqueueSerial {/ / the GCD serial queue synchronization function (immediate execution, the current thread) / / and 1: dispatch_queue_t queue queue / / and 2: Dispatch_sync (queueSerial, ^{for (NSInteger I = 0; i < 10; i++) { NSLog(@"~~~%ld %@",i, [NSThread currentThread]); }}); Dispatch_async (^{dispatch_async(queueSerial, ^{for (NSInteger I = 0; i < 10; i++) { NSLog(@"~~~%ld %@",i, [NSThread currentThread]); }}); dispatch_async(queueSerial, ^{ for (NSInteger i = 0; i < 10; i++) { NSLog(@"~~~%ld %@",i, [NSThread currentThread]); }}); dispatch_async(queueSerial, ^{ for (NSInteger i = 0; i < 10; i++) { NSLog(@"~~~%ld %@",i, [NSThread currentThread]); }}); }); } //3. Create a concurrent queue -(void)runqueueConcurrent {// synchronize the function to the parallel queue (execute immediately, Dispatch_sync (queueConcurrent, ^{for (NSInteger = 0; i < 10; i++) { NSLog(@"~~~%ld %@",i, [NSThread currentThread]); }}); ^{dispatch_async(queueConcurrent, ^{for (NSInteger I = 0; i < 5; i++) { NSLog(@"~~~%ld %@",i, [NSThread currentThread]); }}); dispatch_async(queueConcurrent, ^{ for (NSInteger i = 0; i < 6; i++) { NSLog(@"~~~%ld %@",i, [NSThread currentThread]); }}); dispatch_async(queueConcurrent, ^{ for (NSInteger i = 0; i < 7; i++) { NSLog(@"~~~%ld %@",i, [NSThread currentThread]); }}); }); } //4. Create a global queue -(void)runqueueGlobal {// Get the global queue: the global queue is a concurrent queue // Parameter 1: the priority of the queue // Parameter 2:0(which may be used later)//#define DISPATCH_QUEUE_PRIORITY_HIGH 2 // high \ #define DISPATCH_QUEUE_PRIORITY_DEFAULT 0 // Default (middle) \ #define \ #define DISPATCH_QUEUE_PRIORITY_BACKGROUND INT16_MIN // Dispatch_queue_t queueGlobal = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); } // main queue :(any task in the main queue will be queued to the main thread)Copy the code

If you add task A to A serial queue using sync, it means that task A must be executed immediately in the current serial queue. After task A is executed, the code following task A will be executed. However, the current queue is A serial queue, that is to say, task A must wait until the completion of task B in the current serial queue before it can be executed, so task A must execute the immediate task in task A first, and task B must wait until the completion of the execution of the next task, so it will be stuck. You wait for me, I wait for you, who can not execute.

####GCD implementation thread communication small project: download pictures

The code is as follows:

// Get the url of the image
NSURL *url = [NSURL URLWithString:@"http://7xjanq.com1.z0.glb.clouddn.com/6478.jpg"];

// Start the thread to download the image
dispatch_queue_t queue = dispatch_queue_create("111", DISPATCH_QUEUE_CONCURRENT);

dispatch_async(queue, ^{
    NSData *data = [NSData dataWithContentsOfURL:url];
    UIImage *image = [UIImage imageWithData:data];

    // Return to the main thread to display the image
    dispatch_async(dispatch_get_main_queue(), ^{
        self.imageView.image = image;
    });
});Copy the code

— — — — — — — — — — — — — — — — — — — —

GCD other commonly used functions

image

/ / -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- the queue group -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
// Queue groups can add many queues to a group. The advantage of this is that the queue group will notify us through a method when all tasks in the group have completed. Here's how to use it, which is a very useful feature.- (void)rungroup
{
    //1. Create queue groups
    dispatch_group_t group=dispatch_group_create();
    //2. Create queues
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0);
    //3. Use the queue group method multiple times to execute the task, only asynchronous method
    //3.1. Execute three cycles
    dispatch_group_async(group,queue,^{
        for (NSInteger i = 0; i< 3; i++){
            NSLog(@"group-01 - %@", [NSThread currentThread]); }});//3.2. The main queue executes 8 loops
    dispatch_group_async(group, dispatch_get_main_queue(), ^{
        for (NSInteger i=0; i<8; i++) { NSLog(@"group-02 - %@", [NSThread currentThread]); }});//3.3. Execute five loops
    dispatch_group_async(group, queue, ^{
        for(NSInteger i=0; i<5; i++) { NSLog(@"group-03 - %@", [NSThread currentThread]); }});//4. We will automatically notify you when everything is finished
    dispatch_group_notify(group,dispatch_get_main_queue(),^{
        NSLog(@"Done - %@", [NSThread currentThread]);
    });
}Copy the code

Dispatch_barrier fence

Barrier: the queue preceding the barrier is executed first, then the barrier is executed again, and then the queue after the barrier is executed again cannot be a global concurrent queue
dispatch_queue_t queue = dispatch_queue_create("11", DISPATCH_QUEUE_CONCURRENT);

dispatch_async(queue, ^{
    for (int i = 0;  i < 100; i++) {
        NSLog(@"% @ - 1", [NSThread currentThread]); }}); dispatch_async(queue, ^{for (int i = 0;  i < 100; i++) {
        NSLog(@"% @ - 2", [NSThread currentThread]); }}); dispatch_barrier_async(queue, ^{for (int i = 0;  i < 100; i++) {
        NSLog(@"% @ - 3", [NSThread currentThread]); }}); dispatch_async(queue, ^{for (int i = 0;  i < 100; i++) {
        NSLog(@"% @ - 4", [NSThread currentThread]); }});// Dispatch_after Delays execution
    // Delay execution
    1 / / method
    [self performSelector:@selector(run:) withObject:@"Parameters" afterDelay:2.0];

    2 / / method
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        for (NSInteger i = 0; i < 100; i++) {
            NSLog(@"% @", [NSThread currentThread]); }});3 / / method
    [NSTimer scheduledTimerWithTimeInterval:2.0target:self selector:@selector(run:) userInfo:nil repeats:NO]; Dispatch_once Is executed once during the entire program run// Execute only once in the entire program
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
    // One-time code
});Copy the code

Question to consider: What is the output of the following function?

image

What is the output of the following code

image

Function: Implements a singleton object of a class

Singleton pattern: A resource is shared across the application (this resource only needs to be created and initialized once)

/ / -- -- -- -- -- -- -- -- -- -- -- -- -- -- the singleton pattern -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- # if __has_feature (objc_instancetype) # undef AS_SINGLETON # define AS_SINGLETON ( ...). \ - (instancetype)sharedInstance; \ + (instancetype)sharedInstance; #undef DEF_SINGLETON #define DEF_SINGLETON \ - (instancetype)sharedInstance \ { \ return [[self class] sharedInstance]; \ } \ + (instancetype)sharedInstance \ { \ static dispatch_once_t once; \ static id __singleton__; \ dispatch_once( &once, ^{ __singleton__ = [[self alloc] init]; }); \ return __singleton__; \ } #undef DEF_SINGLETON #define DEF_SINGLETON( ... ) \ - (instancetype)sharedInstance \ { \ return [[self class] sharedInstance]; \ } \ + (instancetype)sharedInstance \ { \ static dispatch_once_t once; \ static id __singleton__; \ dispatch_once( &once, ^{ __singleton__ = [[self alloc] init]; }); \ return __singleton__; \ } #else // #if __has_feature(objc_instancetype) #undef AS_SINGLETON #define AS_SINGLETON( __class ) \ - (__class *)sharedInstance; \ + (__class *)sharedInstance; #undef DEF_SINGLETON #define DEF_SINGLETON( __class ) \ - (__class *)sharedInstance \ { \ return [__class sharedInstance]; \ } \ + (__class *)sharedInstance \ { \ static dispatch_once_t once; \ static __class * __singleton__; \ dispatch_once( &once, ^{ __singleton__ = [[[self class] alloc] init]; }); \ return __singleton__; \} #endif // #if __has_feature(objc_instancetype) #import "gcdFunViewController.h" #pragma mark - singleinstance mode 👆 👇 @interface Person:NSObject //+ (instancetype)shareInstance; AS_SINGLETON(Person) @end @implementation Person DEF_SINGLETON(Person) /* + (instancetype)shareInstance { static id _person; static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ _person = [[super alloc] init]; }); return _person; } */ + (instancetype)allocWithZone:(struct _NSZone *)zone { static id _person; static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ _person = [super allocWithZone:zone]; }); return _person; } - (id)copy { return [Person sharedInstance]; } @endCopy the code

Development in general custom macro, more convenient, a line of code to fix.

Dispatch_apply fast iteration

// Example applet: cut images from one folder to another folder

- (void)testdispatch_apply
{
    // Cut the image into another folder
    NSString *from = @"/ Users/Ammar/Pictures/wallpaper";
    NSString *to = @"/Users/Ammar/Pictures/to";
    NSFileManager *manager = [NSFileManager defaultManager];
    NSArray *subPaths = [manager subpathsAtPath:from];

    // Iterate fast
    dispatch_apply(subPaths.count, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(size_t index) {
        NSLog(@"%@ - %zd", [NSThread currentThread], index);
        NSString *subPath = subPaths[index];
        NSString *fromPath = [from stringByAppendingPathComponent:subPath];
        NSString *toPath = [to stringByAppendingPathComponent:subPath];

        / / shear
        [manager moveItemAtPath:fromPath toPath:toPath error:nil];
        NSLog(@"%@---%zd", [NSThread currentThread], index);
    });

    The first parameter is the number of iterations, the second parameter is the queue, and the third parameter is the current index. Dispatch_apply can take advantage of multiple cores, so the index order of output is not certain
    dispatch_apply(10, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(size_t index) {
        NSLog(@"dispatch_apply %zd",index);
    });
    2016-02-15 10:15:21.229 Multithreaded [4346:48391] dispatch_apply 0 2016-02-15 10:15:21.229 Multithreaded [4346:48784] Dispatch_apply 1 2016-02-15 10:15:21.230 Multi-thread [4346:48830] dispatch_apply 2 2016-02-15 10:15:21.230 Multi-thread [4346:48391] Dispatch_apply 3 2016-02-15 10:15:21.231 Multi-thread [4346:48829] Dispatch_apply 6 2016-02-15 10:15:21.231 Multi-thread [4346:48391] dispatch_apply 9 2016-02-15 10:15:21.230 Multi-thread [4346:48784] Dispatch_apply 8 2016-02-15 10:15:21.231 Multi-thread [4346:48829] dispatch_apply 8 2016-02-15 10:15:21.231 Multi-thread [4346:48829] dispatch_apply 7 */
}Copy the code

Dispatch_group Queue group example applet: Requirement download picture 1 download picture 2 Synthesize picture 1 and picture 2 into a new picture

// Create a queue
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

/ / create a group
dispatch_group_t group = dispatch_group_create();

// Download image 1 with group queue
dispatch_group_async(group, queue, ^{
    NSData *data = [NSData dataWithContentsOfURL:[NSURL URLWithString:@"http://7xjanq.com1.z0.glb.clouddn.com/6478.jpg"]];
    self.image1 = [UIImage imageWithData:data];
    NSLog(@1% "@", [NSThread currentThread]);
});

// Download image 2 with group queue
dispatch_group_async(group, queue, ^{
    NSData *data = [NSData dataWithContentsOfURL:[NSURL URLWithString:@"http://7xjanq.com1.z0.glb.clouddn.com/6478.jpg"]];
    self.image2 = [UIImage imageWithData:data];
    NSLog(@2% "@", [NSThread currentThread]);
});

// Combine picture 1 with picture 2
dispatch_group_notify(group, queue, ^{
    CGFloat imageW = self.imageView.bounds.size.width;
    CGFloat imageH = self.imageView.bounds.size.height;

    // Enable bitmap context
    UIGraphicsBeginImageContext(self.imageView.bounds.size);

    / / drawing
    [self.image1 drawInRect:CGRectMake(0.0, imageW * 0.5, imageH)];
    [self.image2 drawInRect:CGRectMake(imageW * 0.5.0, imageW * 0.5, imageH)];

    // Take out the picture
    UIImage *image = UIGraphicsGetImageFromCurrentImageContext();

    // Turn off the graphics context
    UIGraphicsEndImageContext();

    // Display the image on the main thread
    dispatch_async(dispatch_get_main_queue(), ^{
        self.imageView.image = image;
    });
    NSLog(@3% "@", [NSThread currentThread]);
});Copy the code

####GCD timer GCD timer is not affected by Mode and is more accurate than NSTimer

#pragma mark -(IBAction)buttonTap (id)sender {UIButton * button = (UIButton *)sender; #pragma mark -(IBAction)buttonTap (id)sender {UIButton * button = (UIButton *)sender; button.enabled = NO; Parameter 1: type timer // Parameter 2: handle // Parameter 3:mask pass 0 // Parameter 4: queue (Note :dispatch_source_t is an OC object, Dispatch_queue_t queue = dispatch_geT_global_queue (DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); dispatch_source_t timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue); Int64_t interval = (int64_t)(1.0 * NSEC_PER_SEC); CGD gives us a method to set the start time // Parameter 1:dispatch_time_t when send a time, Start = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0 * NSEC_PER_SEC)); Parameter 1:timer // Parameter 2: start time // Parameter 3: interval // Parameter 4: send 0. 0 is not required. DISPATCH_TIME_NOW Indicates that the current GCD time is expressed in NS dispatch_source_set_timer(timer, start, interval, 0); __block int count = 60; / / 3. Set the callback (that is, each time interval to do something) dispatch_source_set_event_handler (timer, ^ {NSLog (@ "-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- - % @". [NSThread currentThread]); // Stop count if you want to do it 5 times; dispatch_async(dispatch_get_main_queue(), ^{ if (count == 0) { dispatch_source_cancel(timer); [button setTitle: @ "click the countdown" forState: UIControlStateNormal]; button.enabled = YES; } else { [button setTitle:[NSString stringWithFormat:@"%d",count] forState:UIControlStateNormal]; [button setTitle:[NSString stringWithFormat:@"%d",count] forState:UIControlStateDisabled]; }}); }); // 4. Start the timer (resume) dispatch_resume(timer); }Copy the code

GCD has some other functions that we’ll dive into next time!

— — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — about NSOperation finished the GCD, It’s an object-oriented wrapper around the GCD, and it’s easier to use,

  • NSOperation implements multi-threading
  • NSOperation is an abstract class and does not have the ability to encapsulate operations. You must use subclasses of NSOperation

  • NSInvocationOperation

  • NSBlockOperation custom subclass inherits from NSOperation and implements the corresponding internal methods using NSOperation to implement multithreading steps:

  • Example Create a task NSOperation object

  • Create an NSOperationQueue
  • Example Add the NSOperation object to the NSOperationQueue
  • The NSInvocationOperation code is as follows:
NSInvocationOperation *op = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(run) object:nil];

[op start];Copy the code

Note: By default, a call to start does not open a new thread to execute the operation. Instead, the operation is executed synchronously on the current thread. The operation is executed asynchronously only when NSOperation is placed in an NSOperationQueue

  • NSBlockOperation
    NSBlockOperation *op = [NSBlockOperation blockOperationWithBlock:^{// on the main thread NSLog(@"Download 1 -- -- -- -- -- - % @", [NSThread currentThread]); }]; [op addExecutionBlock:^{NSLog(@)] [op addExecutionBlock:^{NSLog(@)"Download 2 -- -- -- -- -- - % @", [NSThread currentThread]);
    }];Copy the code

Custom Operation: need to implement – (void)main method, need to do things in the mian method

  • NSOperationQueue

    useNSOperationQueueCreate queues: primary queues and global queues
// Create another queue (including a serial queue and a concurrent queue). NSOperation objects placed in this queue will be automatically executed in the child thread

NSOperationQueue *queue = [[NSOperationQueue alloc] init];

// Create a main queue. NSOperation objects placed in this queue are automatically executed in child threads
NSOperationQueue *mainQueue = [NSOperationQueue mainQueue];

// Indicates the number of concurrent tasks: that is, the maximum number of concurrent tasks.
queue.maxConcurrentOperationCount = 1; Canceling, suspending, resuming a queue:// The -cancel method of NSOpertion can also stop a single operation
- (void)cancelAllOperations; 
// YES indicates suspending the queue, and NO indicates resuming the queue
- (void)setSuspended:(BOOL)b; NSOperationQueue *queue = [[NSOperationQueue alloc] init]; NSBlockOperation *block1 = [NSBlockOperation blockOperationWithBlock:^{ NSLog(@"download1 -------------- %@", [NSThread currentThread]);
}];

NSBlockOperation *block2 = [NSBlockOperation blockOperationWithBlock:^{
    NSLog(@"download2 -------------- %@", [NSThread currentThread]);
}];

NSBlockOperation *block3 = [NSBlockOperation blockOperationWithBlock:^{
    NSLog(@"download3 -------------- %@", [NSThread currentThread]);
}];

// Add dependencies: Block1 and block2 are executed after block3 is executed. Block3 depends on block1 and block2

// Add dependencies to block3 so that block3 executes after block1 and block2[block3 addDependency:block1]; [block3 addDependency:block2]; [queue addOperation:block1]; [queue addOperation:block2]; [queue addOperation:block3]; Note: You cannot loop dependencies, but you can rely across queues, regardless of which queue the NSOperation object is in. As long as there are two NSOperation objects you can rely on inter-thread communication example: download image// Download the image operation to implement inter-thread communication
[[[NSOperationQueue alloc] init] addOperation:[NSBlockOperation blockOperationWithBlock:^{
    UIImage *image = [UIImage imageWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:@"http://7xjanq.com1.z0.glb.clouddn.com/6478.jpg"]]];

    // Return the main thread[[NSOperationQueue mainQueue] addOperation:[NSBlockOperation blockOperationWithBlock:^{ self.imageView.image = image; }]]. }]].Copy the code

Example: Download images 1 and 2 and combine them

- (void)demo_combinenetworkimage
{
    NSOperationQueue * queue = [[NSOperationQueue alloc] init];

    __block UIImage * image1;
    NSBlockOperation * block1 = [NSBlockOperation blockOperationWithBlock:^{
        NSData *data = [NSData dataWithContentsOfURL:[NSURL URLWithString:@"http://img1.gtimg.com/15/1513/151394/15139471_980x1200_0.jpg"]];
        image1 = [UIImage imageWithData:data];
        NSLog(@"Download pictures 1%@", [NSThread currentThread]);
    }];

    __block UIImage * image2;
    NSBlockOperation * block2 = [NSBlockOperation blockOperationWithBlock:^{
        NSData *data = [NSData dataWithContentsOfURL:[NSURL URLWithString:@"http://img1.gtimg.com/15/1513/151311/15131165_980x1200_0.png"]];
        image2 = [UIImage imageWithData:data];
        NSLog(@"Download pictures 2%@", [NSThread currentThread]);
    }];


    NSBlockOperation * block3 = [NSBlockOperation blockOperationWithBlock:^{

        CGFloat imageW = self.imageView.bounds.size.width;
        CGFloat imageH = self.imageView.bounds.size.height;

        // Enable bitmap context
        UIGraphicsBeginImageContext(self.imageView.bounds.size);

        / / drawing
        [image1 drawInRect:CGRectMake(0.0, imageW * 0.5, imageH)];
        [image2 drawInRect:CGRectMake(imageW * 0.5.0, imageW * 0.5, imageH)];

        // Take out the picture
        UIImage *image = UIGraphicsGetImageFromCurrentImageContext();

        // Turn off the graphics context
        UIGraphicsEndImageContext();

        // Display the image on the main thread
        [[NSOperationQueue mainQueue] addOperation:[NSBlockOperation blockOperationWithBlock:^{
            NSLog(@"Composite image %@", [NSThread currentThread]);
            self.imageView.image = image;
        }]];
    }];

    [block3 addDependency:block1];
    [block3 addDependency:block2];

    [queue addOperation:block1];
    [queue addOperation:block2];
    [queue addOperation:block3];

}Copy the code
  • Application: SDWebImage framework of the bottom of the main function is based on multithreading, using multithreading, we can achieve a small image of the image download. The logic here is actually more complex to achieve small pictures of multiple images download train of thought:

    TIPS: These are some of the main methods, but here are some common methods to pay attention to:

    NSOperation BOOL executing; BOOL finished; // Check whether the task is being executed. Void (^completionBlock)(void); // To set the action to be performed after completion - (void)cancel; // Cancel the task - (void)waitUntilFinished; // Block the current thread until the task finishes executing NSOperationQueue NSUInteger operationCount; // Get the number of queued tasks - (void)cancelAllOperations; // Cancel all tasks in the queue - (void)waitUntilAllOperationsAreFinished; // Block the current thread until all tasks in this queue are completedsetSuspended:YES]; // Pause queue [queuesetSuspended:NO]; / / continue to queueCopy the code

### Thread synchronization

The so-called thread synchronization is a measure taken to prevent the data security problems caused by multiple threads snatching the same resource. Of course, there are many ways to do this, please read below:

Mutex: Adding a mutex to a block of code that needs to be synchronized ensures that only one thread can access the block at a time. @synchronized(self) {// block of code to execute}

  • The original blog www.jianshu.com/p/b91b42235…
  • This is the first time for me to write a blog post and I hope everyone will criticize and correct me
  • If you have any questions, please follow my wechat ExtremeFruit
  • If you are interested, please download the multithreaded DEMO
  • If you like it, just give me a thumbs up!