iOS Memory Management and Multithreading


This post contains my reading notes of the book \<Pro Multithreading and Memory Management>, from the mechanisms of ARC to the usage of Blocks and Grand Central Dispatch.

Memory Management Actions in Objective-C -- Reference Counting

| Action for Objective-C Object |Objective-C Method |
|:-----------:|:------------:|
| Create and have ownership of it|alloc/new/copy/mutableCopy group |
| Take ownership of it   |  retain |
| Relinquish it  |release|
| Dispose of it|dealloc|

###***+(id)alloc***

```objectivec:implementation.m

+ (id) alloc {
    return [self allocWithZone: NSDefaultMallocZone()]; 
}

+ (id) allocWithZone: (NSZone*)z {
    return NSAllocateObject (self, 0, z); 
}

struct obj_layout { 
    NSUInteger retained;
};

inline id
NSAllocateObject (Class aClass, NSUInteger extraBytes, NSZone *zone) {
    int size = /* needed size to store the object */
    id new = NSZoneMalloc(zone, size);
    memset(new, 0, size);
    new = (id)&((struct obj_layout *)new)[1];
}
```
The NSAllocateObject function calls NSZoneMalloc to allocate a memory area. After that, the area is filled with zero and the area pointer is returned.

Objective-C now ignores zones, which was used to prevent memory fragmentation. The alloc method can now be rewritten as:

```objectivec:demo.m
struct obj_layout { 
   NSUInteger retained;
};
+ (id) alloc {
   int size = sizeof(struct obj_layout) + size_of_the_object; 
   struct obj_layout *p = (struct obj_layout *)calloc(1, size); 
   return (id)(p + 1);
}
```
The alloc method returns a memory block filled with zero containing a struct obj_layout header, which has a variable “retained” to store the number of references(reference count).

###***retain***
get reference count value by calling retainCount:

```objectivec:demo.m
id obj = [[NSObject alloc] init]; 
NSLog(@"retainCount=%d", [obj retainCount]);
/*
* retainCount=1 is displayed. */
```
Implementation of retain:

```objectivec:demo.m
- (id) retain{
    NSIncrementExtraRefCount(self);
    return self;
}
inline void NSIncrementExtraRefCount(id anObject) {
    if (((struct obj_layout *)anObject)[-1].retained == UINT_MAX - 1) 
    [NSException raise: NSInternalInconsistencyException
        format: @"NSIncrementExtraRefCount() asked to increment too far"];
    ((struct obj_layout *)anObject)[-1].retained++; }

```
when the variable "retained" overflows, it's incremented.

###***release***

```objectivec:demo.m
- (void) release {
    if (NSDecrementExtraRefCountWasZero(self))
    [self dealloc]; 
}

BOOL
NSDecrementExtraRefCountWasZero(id anObject) {
    if (((struct obj_layout *)anObject)[-1].retained == 0) { 
        return YES;
    } else {
        ((struct obj_layout *)anObject)[-1].retained--; return NO;
    } 
}

```
"retained" decremented.

###***dealloc***

```objectivec:demo.m
- (void) dealloc {
    NSDeallocateObject (self); 
}
inline void NSDeallocateObject(id anObject) {
    struct obj_layout *o = &((struct obj_layout *)anObject)[-1];
    free(o); 
}
```
a chunck of memory desposed.

###***autorelease***
similar to "automatic variable" in C, which is disposed of automatically when the execution leaves the scope.
autorelease means when execution leaves a code block, the release method is called on the object automatically. 

```objectivec:demo.m
- (id) autorelease {
    [NSAutoreleasePool addObject:self]; 
}
```

#ARC(Automatic Reference Counting)
With ARC, "id" and object type variables must have one of the following ownership qualifiers:
***__strong, __weak, __unsafe_unretained, __autoreleasing***
Ownership is properly managed not only by variable scope, but also by assignments between variables, which are qualified with __strong.

Use __weak to avoid circular references:
A __weak ownership qualifier provides a weak reference. A weak reference does not have ownership of the object.

```objectivec:demo.m
id __strong obj0 = [[NSObject alloc] init]; 
id __weak obj1 = obj0;
/*
* variable obj1 has a weak reference of the created object */
```
__unsafe_unretained: don't use it unless you have to support prior to iOS5, it might leave a dangling pointer. use __weak instead.

However, __weak is exclusively for pointers that should be zeroed, not for primitive types.

__unsafe_unretained is useful for situations where you have an object pointer in a situation where ARC doesn't have enough control to safely manage memory, like inside of a regular C struct. That's one reason there's the "no object pointers in C struct" limitation, unless you decorate that point with __unsafe_unretained to let the compiler you know what you're doing. It's also used to break strong-reference cycles (a.k.a. retain cycles) with blocks under some specific circumstances.

But for 99.9% of daily work, weak works great and you can forget about __unsafe_unretained.
[Source](http://forums.bignerdranch.com/viewtopic.php?f=162&t=3313)

#Blocks
A Block is generated from the Block literal starting with “^”. And the Block is assigned to the variable “blk”. Of course you can assign the value to other variables of the Block type.

Blocks are Anonymous functions together with automatic(local)variables.

***Declarations*** （[source](http://goshdarnblocksyntax.com )）
As a local variable:
***returnType (^blockName)(parameterTypes) = ^returnType(parameters) {...};***

As a property:
***@property (nonatomic, copy) returnType (^blockName)(parameterTypes);***

As a method parameter:
***(void)someMethodThatTakesABlock:(returnType (^)(parameterTypes))blockName;***

As an argument to a method call:
***[someObject someMethodThatTakesABlock: ^returnType (parameters) {...}];***

As a typedef:
***typedef returnType (^TypeName)(parameterTypes);
TypeName blockName = ^returnType(parameters) {...};***


```objectivec:block.m
int (^blk1)(int) = blk;
int (^blk2)(int); blk2 = blk1;
/*Functions can take arguments of Block type.*/
void func(int (^blk)(int)) {
/*Also, functions can return a Block.*/
int (^func()(int)) {
return ^(int count){return count + 1;};
}
```
Using typedefs:

```objectivec:block.m
typedef int (^blk_t)(int);
```

#Grand Central Dispatch
How to use: define tasks you want to execute and add them to an appropriate dispatch queue.

```objectivec:GCD.m
dispatch_async(queue_for_background_threads, ^{ 
/*
* Here, processing a time-consuming task
*
* The task is completed. Then, use the result on the main thread as follows. 
*/
    dispatch_async(dispatch_get_main_queue(), ^{
    /*
    * Here, tasks that work only on the main, such as         
    * updating user inteface, etc.
    */
    }); 
});
```
Dispatch Queues
A dispatch queue is a queue to store tasks to be executed (in the added, first in first out order).

###Two kinds of dispatch queues:
- ***serial dispatch queue***: waits until the current running task finishes before starting another task, only one task runs at a time.
- ***concurrent dispatch queue***: whether the first task is finished or not, the second may start.It doesn't wait until the tasks are finished and multiple tasks can run concurrently. The number of tasks running concurrently depends on the status of the current system(on iOS the XNU kernel decides the number of threads).

When a concurrent dispatch queue is used, the execution order depends on the task themselves, the system status and so on. the order of the tasks isn't constant. You should use serial dispatch queue when the order is important or the tasks shouldn't be running concurrently.

###Two ways to obtain dispatch queues:
- ***dispatch_queue_create***: a function for creating a new dispatch queue.

```objectivec:serialQueue.m
dispatch_queue_t mySerialDispatchQueue = dispatch_queue_create("com.example.gcd.MySerialDispatchQueue", NULL);
```
Use serial dispatch queues only to avoid race condition that occurs because multiple threads update the same data. Otherwise avoid it, too many threads consume too much memoery and the system to slow down.

dispatch queues are not treated as Objective-C objects, you have to call dispatch_release when it's no longer needed. Dispatch queues are managed by dispatch_retain and dispatch_release functions with reference counting techniques.

```objectivec:concurrentQueue.m
dispatch_queue_t myConcurrentDispatchQueue = dispatch_queue_create( "com.example.gcd.MyConcurrentDispatchQueue", DISPATCH_QUEUE_CONCURRENT);
dispatch_async(myConcurrentDispatchQueue, ^{NSLog(@"block on myConcurrentDispatchQueue");});
dispatch_release(myConcurrentDispatchQueue);
```
- ***main dispatch queue / global dispatch queue***:

The main dispatch queue is a serial dispatch queue to execute tasks on the main thread.

The global dispatch queues are concurrent dispatch queues that are usable anywhere in the app. There are four global dispatch queues with different priority: *high, default, low* and *background*.

```objectivec:globalDispatchQueues.m
/*
* How to get the main dispatch queue */
dispatch_queue_t mainDispatchQueue = dispatch_get_main_queue();
/*
* How to get a global dispatch queue of high priority */
dispatch_queue_t globalDispatchQueueHigh = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0);
/*
* How to get a global dispatch queue of default priority */
dispatch_queue_t globalDispatchQueueDefault = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
￼/*
* How to get a global dispatch queue of low priority */
dispatch_queue_t globalDispatchQueueLow = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0);
/*
* How to get a global dispatch queue of background priority */
dispatch_queue_t globalDispatchQueueBackground = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0);
```
Dispatch Groups: a group of 	queues

```objectivec:dispatchGroups.m
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_group_t group = dispatch_group_create();
dispatch_group_async(group, queue, ^{NSLog(@"blk0");}); dispatch_group_async(group, queue, ^{NSLog(@"blk1");}); dispatch_group_async(group, queue, ^{NSLog(@"blk2");});
dispatch_group_notify(group, dispatch_get_main_queue(), ^{NSLog(@"done");});
dispatch_release(group);
/*output:
blk1
blk2
blk0
done*/
```
###GCD functions
- ***dispatch_set_target_queue***: to modify the priority of a dispatch queue after it is created.
- ***dispatch_after***:setting the timing to start tasks in the queue.

```objectivec:dispatch_after.m
dispatch_time_t time = dispatch_time(DISPATCH_TIME_NOW, 3ull * NSEC_PER_SEC); dispatch_after(time, dispatch_get_main_queue(), ^{
NSLog(@"waited at least three seconds."); });
```
- ***dispatch_barrier_async***:waiting for other tasks in a queue. You can add a task to a concurrent dispatch queue at the time all the tasks in the queue are finished.When the task added by the dispatch_barrier_async function is finished, the concurrent dispatch queue will be back to normal, which means that it executes the tasks concurrently.

- ***dispatch_sync***: adds the block to the dispatch queue synchronously. Use carefully since it may cause deadlocks.

- ***dispatch_apply***:add a block to a dispatch queue for a number of times.
- ***dispatch_suspend/dispatch_resume***:suspend or resume the execution of the queue.

- ***dispatch_once***:used to ensure that the specified task will be executed only once during the application's lifetime(oftenly used to initialize a singleton class).

```objectivec:singleton.m
+ (id)sharedManager {
    static MyManager *sharedMyManager = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        sharedMyManager = [[self alloc] init];
    });
    return sharedMyManager;
}
```
Summary: this article serves as a quick reference to iOS memory management and multithreading related topics.  In the future, if I find particular cases interesting, I will come back to update this article.