Good articles to my personal technology blog: https://cainluo.github.io/15062229631553.html
Last article, we briefly talked about some Tips to use GCD, if you do not watch the friends, you can play iOS development: combat development GCD Tips (a) look.
This time, we’ll continue with the tips.
Reprint statement: if you need to reprint this article, please contact the author, and indicate the source, and can not modify this article without authorization.
Flexible use of queue groups
When we use queue groups to perform tasks, this is usually the case:
- (void)queueGroup {
dispatch_queue_t queue = dispatch_queue_create("queue", DISPATCH_QUEUE_CONCURRENT);
dispatch_group_t group = dispatch_group_create();
dispatch_group_async(group, queue, ^{
NSLog(@" Execute task, current thread :%@"[NSThread currentThread]);
});
}
Copy the code
Printed results:
2017-09-24 11:34:44.766052+0800 CMD-tips [59653:3482075] 2017-09-24 11:34:44.766606+0800 CMD-tips [59653:3482075] <NSThread: 0x604000464980>{number = 3, name = (null)}Copy the code
There are other ways to use dispatch_group_enter and dispatch_group_leave. Note that both methods are present at the same time:
- (void)gourpEnterAndLeave {
dispatch_group_t group = dispatch_group_create();
dispatch_group_enter(group);
[self urlRequestSuccess:^{
NSLog(@" Network request successful");
dispatch_group_leave(group);
} failure:^{
NSLog(@" Network request failed");
dispatch_group_leave(group);
}];
}
- (void)urlRequestSuccess:(void(^)())success
failure:(void(^)())failure {
success();
// failure();
}
Copy the code
Printed results:
2017-09-24 11:46:16.054410+0800 GCD-Tips[60002:3501228[enter into operation2017-09-24 11:46:16.054721+0800 GCD-Tips[60002:3501228The network request succeededCopy the code
This way, we can wrap up the network request, but be careful not to call both dispatch_group_leave at the same time, otherwise it will hang.
If we want to add an end task, we can do it in two ways:
- dispatch_group_notify
- It is called after the current queue group task has finished executing
dispatch_group_notify
To let you know the mission is over.
- It is called after the current queue group task has finished executing
- dispatch_group_wait
- and
dispatch_group_notify
Similar, except that you can add the delay end time, but there is a point to note here,dispatch_group_wait
Blocks the current thread, so do not use theThe main thread
Or it blocks the main thread.
- and
Dispatch_barrier_ (a) Sync usage notes
We all know that dispatch_barrier_(a)sync is a barrier method that inserts a block into a queue and waits until that block is complete before executing another queue.
- (void)queueBarrier {
dispatch_queue_t queue = dispatch_queue_create("queueBarrier", DISPATCH_QUEUE_CONCURRENT);
dispatch_async(queue, ^{
NSLog("Execute one, current thread :%@"[NSThread currentThread]);
});
dispatch_barrier_async(queue, ^{
NSLog(@" Big guy is coming, current thread :%@"[NSThread currentThread]);
});
dispatch_async(queue, ^{
NSLog(@" Execute two, current thread :%@"[NSThread currentThread]);
});
}
Copy the code
Printed results:
2017-09-24 12:44:36.151126+0800 CMD-tips [61121:3585236] 2017-09-24 12:44:36.151579+0800 CMD-Tips [61121:3585334] <NSThread: 0x600000462E40 >{number = 3, name = (null)} 2017-09-24 12:44:36.152335+0800 CGC-TIPS [61121:3585334] Current thread :<NSThread: 0x600000462E40 >{Number = 3, name = (null)} 2017-09-24 12:44:36.154241+0800 CD/Tips[61121:3585334] 0x600000462e40>{number = 3, name = (null)}Copy the code
PS: dispatch_barrier_(a)sync
It’s only valid if it’s on a self-created concurrent queue, if it’s on a global concurrent queue, serial queue,dispatch_(a)sync
The effect is the same, in this case, it is easy to cause thread deadlock, so be careful here.
Dispatch_set_context and dispatch_set_finalizer_f
Two things to add here, dispatch_set_context and dispatch_set_finalizer_f.
- Dispatch_set_context: Context data can be added to the queue
- Dispatch_set_finalizer_f: transfers memory management rights
Note that dispatch_set_context accepts the context parameter as a C language parameter.
typedef struct _Info {
int age;
} Info;
void cleanStaff(void *context) {
NSLog(@"In clean, context age: %d", ((Info *)context)->age);
// If the object is new, use delete
free(context);
}
- (void)setContext {
dispatch_queue_t queue = dispatch_queue_create("contextQueue", DISPATCH_QUEUE_SERIAL);
// Initializes the Data object and sets the initialization value
Info *myData = malloc(sizeof(Info));
myData->age = 100;
/ / binding Context
dispatch_set_context(queue, myData);
// Set the finalizer function to release the context memory after the queue execution is complete
dispatch_set_finalizer_f(queue, cleanStaff);
dispatch_async(queue, ^{
// Get the queue context data
Info *data = dispatch_get_context(queue);
/ / print
NSLog(@"1: context age: %d", data->age);
// Modify the data saved by the context
data->age = 20;
});
}
Copy the code
Print the result:
2017-09-24 14:24:10.394129+0800 GCD-Tips[61881:3652088[enter into operation2017-09-24 14:24:10.394547+0800 GCD-Tips[61881:3652274] 1: context age: 100
2017-09-24 14:24:10.394738+0800 GCD-Tips[61881:3652274] In clean, context age: 20
Copy the code
PS: We diddispatch_set_context
Be sure to release it, or you’ll cause a memory leak.
In addition to that, we can do things with Core Foundation, so how do we do that?
NSObject and dispatch_set_context
Here we create a Model class that inherits NSObject:
@interface GCDModel : NSObject
@property (nonatomic.assign) NSInteger age;
@end
@implementation GCDModel
- (void)dealloc {
NSLog(@"%@ released".NSStringFromClass([self class]));
}
@end
Copy the code
In this class, we simply operate with a single attribute and a dealloc method:
void cleanObjectStaff(void *context) {
GCDModel *model = (__bridge GCDModel *)context;
NSLog(@"In clean, context age: %ld", model.age);
// Free memory
CFRelease(context);
}
- (void)objectAndContext {
dispatch_queue_t queue = dispatch_queue_create("objectQueue", DISPATCH_QUEUE_SERIAL);
// Initializes the Data object and sets the initialization value
GCDModel *model = [[GCDModel alloc] init];
model.age = 20;
// Bind Context, where the __bridge key is used
dispatch_set_context(queue, (__bridge_retained void *)(model));
// Set the finalizer function to release the context memory after the queue execution is complete
dispatch_set_finalizer_f(queue, cleanObjectStaff);
dispatch_async(queue, ^{
// Get the queue context data
GCDModel *model = (__bridge GCDModel *)(dispatch_get_context(queue));
/ / print
NSLog(@"1: context age: %ld", model.age);
// Modify the data saved by the context
model.age = 120;
});
}
Copy the code
Print the result:
2017-09-24 14:40:34.024509+0800 GCD-Tips[62448:3676807[enter into operation2017-09-24 14:40:34.024915+0800 GCD-Tips[62448:3676887] 1: context age: 20
2017-09-24 14:40:34.025236+0800 GCD-Tips[62448:3676887] In clean, context age: 120
2017-09-24 14:40:34.025706+0800 GCD-Tips[62448:3676887The GCDModel is releasedCopy the code
Here we explain the __bridge keyword:
- __bridge: only type conversion, no memory management permission modification.
- __bridge_retained: memory translation
(CFBridgingRetain)
And change the memory management permissions fromARC
Take it to yourself and use it for final releaseCFRelease
To release the object. - __bridge_transfer:
Core Foundation
Converted toObjective-C
object(CFBridgingRelease)
And give the memory management authorityARC
.
Why take memory management into your own hands and not ARC?
The truth is simple, if ARC is in charge, your object will be released as soon as it detects that it is done.
You can’t add the Context to the queue, it will give you a wild pointer error, so we need to do it ourselves to make sure that ARC doesn’t release it.
The above code is also easy to interpret:
- in
dispatch_set_context
When using__bridge_retained
To convert, willContext
The memory management rights to our own hands for management. - In the case of queued tasks, we use
dispatch_get_context
In order to getcontext
Use keywords__bridge
Make the switch, so that it can be maintainedcontext
The memory management rights remain unchanged, preventing out of scopeContext
They will be released. - In the end,
CFRelease
To releasecontext
This ensures that the memory is released without causing memory leaks.
conclusion
Ok, the extra GCD tips are almost here, if there are more tips will continue to update, welcome friends and I share other tips ~~
Here are a few recommended articles:
Grand Central Dispatch (GCD) Reference Concurrency Programming Guide Toll-Free Bridged Types
The project address
The address of the project: https://github.com/CainRun/iOS-Project-Example/tree/master/GCD-Tips/GCD-Tips-Two