“Effective Objective-C 2” third reading notes

Statement: This is a series of notes every morning I turn on the computer first thing to do, of course, use a lot of time is not because I have other things to do, although it had bought a paper book but take notes and see when are the basic electronic version, a total of 52 points per Tip. A Tip I was completely transcribed, afraid to say do not understand so fair is to strengthen the memory, I will continue to modify all the relevant point of their future encounter are added, finally I hope readers to respect the original, buy genuine books. PS: do not like to enjoy the reward

GitHub code URL, we have to give an incentive to Star ah.

The whole series of notes

“Effective Objective-C 2” the first reading notes
“Effective Objective-C second” reading notes
“Effective Objective-C 2”, the third reading notes

The sixth chapter block and GCD (block and Grand Central Dispatch)

“Block” is a kind of the C, using C++ and Objective-C syntax closure code “(lexical closure)”, through this mechanism, developers can tell the code as it passed, running in different situations.
GCD is a block – related technique that provides an abstraction of the thread, which is based on the queue (dispatch)”. Developers can block into the queue, the GCD is responsible for handling all calls. GCD according to the system resources, the timely creation, reuse, destroy the background thread.

37 understand the concept of “block”

The basic knowledge of blocks is similar to the function of the
block, but is directly defined in another function, and the function that defines it shares the same range of things. The block is represented by the ^ symbol followed by curly braces.

Int additional __ block int = 5; iSu = 8; int (addBlock ^ (int) a, int (b) = int int b ^ A, return) {a + B + additional; iSu++;} int add = addBlock (2,5) / / add = 12

When declared variables can be added _ _block modifier, so that we can modify in the block.

If the variable captured by the block is an object type, it will automatically retain it. The system releases it when it releases it. It is an important problem that leads to a block. Block itself can be viewed as an object. Reference count. When the last reference to the block is removed, the block is recovered.

If the block is defined in the instance method of OC, you can use the self variable in addition to all of the instances of the class. The block can always modify instance variables, so it is not necessary to add __block. However, if the instance variable is associated with an instance of the self. For example, this block is declared in the EOCClass class method.

@interface EOCClass - (void) anInstancemethod{void (^someBlock)) = ^{(_anInstanceVariable = "Something"; NSLog (@ _anInstanceVariable =% @ ", _anInstanceVariable);}}

If an instance of EOCClass is executing the anInstanceMethod method, the self variable points to this instance. Because the block does not explicitly use the self variable, it is easy to forget that the self variable is actually captured by the block. Direct access to instance variables and access through self is equivalent.
self -> _anInstanceVariable = @ Something @;
then this situation will result in the “reserved ring”.

Block memory layout:

fast object memory layout.Png

The first variable of
is a pointer to the Class object, which is called isa. The rest of the memory contains all the information needed for the normal operation of the block object.

  1. Invoke variable, which is a function pointer, the realization of the code block. The function prototype must accept at least one argument of type void *, which represents the block.
  2. The descriptor variable is a pointer to the structure, each of which contains the structure, in which the size of the block object is declared, and the function pointer corresponding to the two auxiliary functions of copy and dispose is declared. Auxiliary function when copying and discarding block objects. The
    block copies all the variables that are captured. Behind descriptor. Capture a number of variables, how much memory space will be occupied. Note that the copy is not the object itself, but a pointer to the object. Used in the execution of the block, from the memory of these captured variables read out.

Global block, stack block, and heap block
define blocks, the memory area is allocated in the stack, that is to say, the block is only valid within the scope of its definition.

Void (^block) (); if (some condition) {block = ^ {NSLog (@ Block A);}} else {block = ^ {NSLog (@ Block B);}} ();

The solution to this problem is to send copy messages to copy.

If (some condition) {block = NSLog ([^{@ "Block A");} copy] {block = NSLog;}else [^{(@ "Block B copy]");};}

So there are other articles related to the type of block classification:

  1. The global block (_NSConcreteGlobalBlock) block is either empty block or is not accessible to any external variable of block. It is neither in the stack nor in the heap.
  2. Stack block (_NSConcreteStackBlock) block closure behavior, there is access to external variables, and block only and only once, because the stack space is reusable, so when the stack block executed once after will be emptied out of the stack, so can not be used repeatedly.
  3. Heap block (_NSConcreteMallocBlock) block has a closure behavior, and the block needs to be executed multiple times. When multiple execution is required, the block is copied from the stack to the heap.
Main points:
  • Block is the word closure in C, C++, Objective-C.
  • Acceptable parameters or return values.
  • Blocks can be allocated on the stack or heap, or can be global. The block that is assigned to the station can be copied to the heap, so that it has the reference count as well as the standard Objective-C object.

38 create typedef for common block types

Main points:
  • To redefine the block type with typedef, you can make it easier to use block variables.
  • When defining a new type, you should be aware of the existing naming conventions, and do not conflict with other types of names.
  • You can define multiple types of aliases for the same signature. If the code to be reconstructed uses an alias for the block type. Then only need to modify the corresponding typedef block signature can not change other tyoedef.

39 use handler block to reduce the degree of code dispersion

IOS has a name called “watchdog” (system monitor), after discovering that the main thread of an application has been blocked for some time, it will terminate.
asynchronous method in the implementation of the task, you need to notify the relevant code in some way. There are many ways to achieve this function. A common technique is to design a delegation protocol that enables the object concerned about the event to comply with the agreement.
in this case I need to re engineer the specification of the delegate model:
first if we want a class to monitor another class of properties, then.
is in that class

@protocol EOCNetworkFecherDelegate< NSObject> (void) newworkFetcher: (EOCNetworkFetcher *) networkFether didFinishWithData: (NSData *) data; @end

Then give a delegate attribute
(nonatomic, weak) ID &lt that needs to be assigned to the monitor class; EOCNetworkFetcherDelegate> delegate;

Because it is to monitor a data property, so in the monitored class in the.M file we need:
[_delegate newworkFether:networkFether didFinishWithData:data]
; and then monitor the class we first is the
EOCNetworkFecher object newEOC newEOC.delegate = self;

Then realize newworkFecher didFinishWithData:

(void) newworkFetcher: (EOCNetworkFetcher *) networkFether didFinishWithData: (NSData *) data{do data data collected for the relevant countermeasures. }

The Tip theme:
so now if we want to pass the block to monitor the words:
is listening class:

Typedef void (iSuNetWorkFecherCompletionHandler ^ (NSData) data, NSError * error); @interface iSuNetWorkFetcher NSObject (void) iSuStartWithCompletionHandler: (iSuNetworkFecherCompletionHandler) completion; then.M transfer value inside the inside of the block (void) iSuStartWithCompletionHandler: (iSuNetworkFecherCompletionHandler) completion{int a = 5; NSError * error; completion (a, error);}

Then listen to the class inside.
is the first object iSuTest.

[iSuTest iSuStartWithCompletionHandler:^ (int data, NSError * error) {NSLog (@ "monitor over value:% @", data);}];
Main points:
  • When you create an object, you can use the inline handler block to declare the relevant business logic.
  • When there are multiple instances of the need to monitor, if the principal mode, so often need to switch according to the incoming object, and if the switch to handler block to achieve, can be directly to the block and related objects together.
  • If you use the handler block design API, then you can add a parameter, so that the caller can use this parameter to decide which block should be arranged in the queue on which to perform.

40 do not use a retaining ring when referencing its object

//EOCNetworkFetcher.h #import < Foundation/Foundation.h> typedef; void (^EOCNetworkFetcherCompletionHandler) (NSData * data) @interface EOCNetworkFether:NSObject @property (nonatomic, strong, readonly) NSURL * URL; (ID) initWithURL: (NSURL * URL); (void) startWithCompletionHandle: (EOCNetworkFetcherCompletionHandler) completion @end //EOCNetworkFetcher.m #import "EOCNetworkFetcher.h" @interface (EOCNetworkFetcher) (nonatomic, strong, @property readwrite) NSURL *url @property (nonatomic, copy); EOCNetworkFetcherCompletionHandler completionHandler; @property (nonatomic, strong) NSData * downloadedData; @implementation EOCNetworkFetcher (ID) initWithURL: (NSURL * url{) if (slef = [super init]) {_url = URL;} return self;} (void) startWithCompletionHandler: (EOCNetworkFetcherCompletionHandler) completion{self.completionHandler = completion; //Start the request; //Request sets downloadedData property request is / / When finished, p_requestCompleted is called;} (void) p_requestCompleted{if (_completionHandler) _completionHadnler (_downloadedData) {}};

Another class may create this network data acquisition object

@implementation EOCClass {EOCNetworkFetcher * _networkFethcer; NSData * _fetchedData;} - (void) downLoadData{NSURL * URL =[nsurl @ alloc]initWithString: "www.baidu.com"; _networkFethcer =[EOCNetworkFetcher alloc]initwithURL:url]; _networkFethcer [startWithCompletionHandler:^ (NSData * data) {NSLog: (url = @ "% @ ', _networkFethcer.url); _fetchedData = data;}]};

This code doesn’t seem to be a problem. But there is a circular reference.
but because handler inside to set _fechedData = data, so handler is to hold self (EOCClass). The instance EOCClass holds the network acquisition device through the attributes.

The solution is either to make the _networkFetcher instance variable no longer refer to the collector, or to make the completionHandler property of the handler no longer hold the block. In this example, you should wait for the comletion handler block to be completed, and then break the reservation ring, such as:

[_networkFecher startWithCompletionHandler:^ (NSData * data) {NSLog (@ Request for URL:%@ finished ", _networkFetcher.url); _fetchedData = data; _networkFetcher = nil;}];

But this situation is very free in the implementation of the handler will call, if the completion handler has not run, then the retention ring can not be broken, memory will be leaked.
we can try not to hold properties _fetchedData

(void) setcondDownload{NSURL * URL =[[NSURL alloc]initWithString:@ "www.baidu.com"]; SecondYearNetworkFetcher * networkFetcher =[[SecondYearNetworkFtcher alloc] initWithURL:url]; [networkFetcher startWithCompletionHandler:^ (NSData *data) {NSLog ("% @ @", networkFetcher.url); _fetchedData = data;}]};

/ / is a local variable networkFetcher
; but this also contains the retention ring;
handler is because access to the website by networkFecher then hold this class.
but this networkFecher and through block to hold handler;

The solution is to set the completionHandler property to nil when the block is running

(void) p_requestCompleted{if (_completionHandler) {_completionHandler (_downloadedData);} self.completionHandler = nil;}

In this way, as long as the download request is completed, the reservation ring is lifted.

Main points:
  • If the block captures the object itself directly or indirectly, care must be taken to preserve the ring.
  • Be sure to find the right time to release the ring, not the responsibility of the API to the caller.

41 multi use distribution queue, less synchronous lock

Two ways to add a lock:

(void) synchronizedMehod{@synchronized (self) {}} or _lock =[NSLock alloc] (void) synchronizedMethod{[_lock init]; lock] //safe; [_lock unlock];}

This is also a way to determine when the property is set to be non atomic, rather than the safety of the atomic thread.
because of the abuse that is, each attribute is the use of atomic words will be all synchronization will quickly grab the same lock each other. If there are a lot of attributes that are written, then the synchronization block of each attribute must wait for all other synchronization blocks to be executed. And the property of this kind of knowledge provides a degree of “safety” (thread), but can not guarantee access to the object is absolutely thread safe.

There is a simple and efficient way to replace a synchronization block or lock object, which is a “serial synchronous queue””.
_syncQueue = dispatch_queue_create (“com.effectiveobjective.syncQueue”, NULL)
this last parameter “0” when it is parallel, NULL is the serial should know it.

- (NSString*) someString{__ block NSString * localSomeString; dispatch_sync (_syncQueue, ^{localSomeString = _someString;}); return localSomeString;} - (void) setSomeString: (NSString *) someString{dispatch_sync (_syncQueue ^{, _someString = someString;}});

This will become a synchronization, optimize the settings of the value is not synchronized,

- (void) setSomeString: (NSString *) someString{dispatch_async (_syncQueue ^{, _someString = someString;}});

From the point of view, this small change can improve the setting method of execution speed, but if you check the performance of the program, you will probably find this style than the original slow, because the execution time of asynchronous distributed, need to copy the block. If the block inside the operation is relatively simple, then the running time will slow down, but if it will be a little faster.

So the second question, we want to read and write a property. When you read, you can write, but stop writing when you write.
at this time we can synchronize the concurrent block of the fence to try your next effect.

_syncQueue = dispatch_get_global_queue (DISPATHC_QUEUE_PRIOPRTY_DEFAULT, 0); - (NSString *) someString{_ _ block NSString * localSomeString; dispathch_sync (_syncQueue, ^{localSomeString = _someString;}); return localSomeString;} - (void) setSomeString: (NSString *) someString{dispatch_barrier_async (_syncQueue ^{, _someString = someString;}})

Such a parallel fence queue is faster than serial. This means you have to wait for set to finish the get method.

Main points:
  • Distribution queues can be used to express NSLock (synchronization semantic), which is simpler than using a @synchronized block or an object.
  • By combining synchronous and asynchronous dispatch, it can achieve the same synchronization behavior as the common locking mechanism, but it will not block the thread that is executed asynchronously.
  • Using synchronous queues and barrier blocks, the synchronization behavior is more efficient.

42 multi use GCD, less performSelector series method

On the perform method:
object call the perfome method returns the type is ID, although it can be void, if you want to return to the integer or floating-point type that requires a complex conversion operation. And this conversion is prone to error. There are several versions of performSelector, you can send a message by passing parameters.
so compare GCD and perform methods we often choose GCD.

[self performSelector:@selector (doSomething) withObject:nil afterDelay:5.0]; //Using dispatch_after dispatch_time_t time = dispatch_time (DISPATCH_TIME_NOW (int64_t) (5 * NSEC_PER_SEC)); dispatch_after (time, dispatch_get_main_queue), [self doSomething] (^{})

Two forms of the main thread of the comparison task:

[self performSelectorOnMainThread:withObject:waitUntilDone:]; //Using dispathc_async dispathc_async (dispathc_get_main_queue), ^{([self doSomething];});
Main points:
  • The performSelector series method is easy to be careless in memory management method. It is not possible to determine what the selector is going to be, so the ARC compiler cannot insert the appropriate memory management method.
  • The selection of the performSelector series method is too limited, the return value type of the selector and the number of parameters that are sent to the method are restricted.
  • If you want to put the task on another thread, then it is best not to use the performSelector series method, but the task should be packaged into a block, and then call the GCD method to achieve.

43 master the use of GCD and operation queue

The benefits of NSOperationi and NSOperationQueue are as follows:

  1. Cancel an operation. If you use the distribution queue, then cancel an operation is troublesome, he only exists fire and forget. The operation queue as long as the cancel method can be called.
  2. Specify dependencies between operations. GCD can complete the operation in response, but many tasks to do the math logic. The operation queue call addDependency on it.
  3. Monitoring the properties of the NSOperation object through the key observation mechanism. NSOperation has a lot of attributes to be monitored. Attributes such as isCancelled.
  4. Specify the priority of the operation.
  5. The reuse of NSOperation object
    such as NSBlockOperation object, use is: First: NSBlockOperation
    * block1 =[NSBlockOperation blockOperationWithBlock:^{NSLog (@ block call method “);}]; [block1 setCompletionBlock:^{NSLog (@” end call “);}]; [block1 start]; second
    NSBlockOperation * OP1 =[NSBlockOperation alloc] explain in detail the init]; [op1 addExecutionBlock:^{sleep (10) NSLog (@” the first thread first task “);}]; [op1 addExecutionBlock:^{sleep (4) NSLog (@ second threads of the first task”);}]; [op1 addExecutionBlock:^{sleep (6) NSLog (@ “the first thread second tasks”);}] Conclusion: this method of loading the thread will only be two why not three or more?
Main points:
  • In solving the problem of multi thread and task management, the distributed queue is not the only solution.
  • The operation queue provides a high-level Objective-C API, to achieve the pure GCD is the majority of the functions, but also to achieve more complex operation, the operation if the switch to GCD, is also required to write code.

44 through the Disptch Group mechanism, according to the system resources to perform tasks

This is the main dispatch group or parallel queue, because there is no meaning serial.

Create via dispatch_group_dispatch_group_create ();
add tasks to group:

Void dispatch_group_async (dispatch_group_t group, dispatch_queue_t queue, dispatch_block_t block);
Dispatch_group_wait (dispatch_group_t group, dispatch_time_t time);

This method is the end of group. It’s a kind of blockage

Dispatch_group_notify (dispatch_group_t group, dispatch_queue_t queue, dispatch_block_t block);

This method is a block that is called after the end of the dispatch group.

Main points:
  • A series of tasks can be incorporated into a dispatch group. Developers can get notifications when this group is finished.
  • Through the dispatch group, you can perform a number of tasks in a distributed queue. At this point, GCD will schedule these concurrent tasks according to the system resources. Developers themselves to achieve this feature, you need to write a large number of aunt.

45 use dispatch_once to perform thread safe code that runs only once

The singleton pattern we used before is the:

- (ID) sharedInstance{static EOCClass * shared = nil; @synchrnized (self) {if (sharedInstance! = [[self) {sharedInstance}} alloc] init]; return shared;}

The reason for using the @synchrnized synchronization lock is thread security.

Thread security issues;
basic is the same resource is set at the same time the conflict between different threads.
and then we often use the dispatch_once method to prepare a single case method:

- (ID) iSuSharedInstance{static EOCClass * shared = nil; static dispatch_once_t onceToken; dispatch_once (& onceToken, shared = [[self ^{alloc] init]; return shared;}})

It is proved that the running speed of GCD method is two times higher than that of synchronous lock block.

Main points:
  • Often need to write only need to execute a thread safety code (thread-safe single-code execution)”. Through the GCD function provided by dispathc_once, it is easy to achieve this function.
  • The tag should be declared in the static or global scope, so that when the block that is executed only once is passed to the dispatch_once function, the same token is passed.

46 do not use dispatch_get_current_queue

Destructor: a function called when an object is destroyed.
we look at the following two functions

- (NSString *) someString{__block NSString * localSomeString; dispatch_sync (_syncQueue, localSomeString = ^{_ someString; return; localSomeString;}}) - (void) setSomeString: (NSString *) someString{dispatch_async (_syncQueue ^{, _someString = someString;}});

Access method may be deadlock (EXC_BAD_INSTRUCTION)

What is the meaning of Deadlock:
I see is a single person to do a task, then the task is bharara Bala task, so the person want to do is to put the Balabala tasks done, but this is also a task of Ladd was added to the synchronization the inside of the task queue. Because the task list is not a stack type (LIFO) but an advanced go out (FIFO) queue so that people want to accomplish all tasks must complete the task queue outside, and then complete the task Balabala internal queue. So the task stops at the first appearance, and the internal Balabala tasks also need to perform, because this person has been the first task to hold, it is not possible to run to do second things, second tasks to finish tasks also led to the first return to finish. Hey, yeah, what did I write?.

Deadlock exists when the get and set methods are called together.

This brings out why not use dispatch_get_current_queue.
solution contains a judge is not a synchronization queue, if it is a direct block () to achieve, if not on the normal queue to join.

- (NSString * someString{) _ _block NSString * localSomeString; dispatch_block_t accessorBlock = ^{localSomeString = _someString;}; if (dispathc_get_current_queue) (= = _syncQueue) {(accessorBlock);}else (_syncQueue, accessorBlock) {dispatch_sync}};

This is certainly not a problem, but if it is a nested queue

Dispatch_queue_t queueA =dispatch_queue_create (com.effective.queueA, NULL); dispatch_queue_t queueB =dispatch_queue_create (com.effective.queueB, NULL); dispatch_sync (queueA, NSLog ^{(@ "first A"); dispatch_sync (queueB, NSLog ^{(@ second "B"); dispatch_sync (queueA, ^{(NSLog @ third C ");});});});

This time even if the use of getCurrent method to get the queue queue is also queueB, the same will produce deadlock.
to solve this problem, the best way is to provide the functionality provided by the GCD to set the queue specific data (queue-specific data)

Dispatch_queue_t queueC = dispatch_queue_create (com.effectiveobjectivec.queueC, NULL); dispatch_queue_t queueD =dispatch_queue_create (com.effectiveobjectivec.queueD, NULL); / / will give priority to the operation of D C dispatch_set_target_queue (queueD, queueC); static int kQueueSpecific; CFStringRef queueSpecificValue = CFSTR ("queueC"); dispatch_queue_set_specific (queueC, & kQueueSpecific (void * queueSpecificValue), CFRelease (dispatch_function_t)); dispatch_sync (queueD, block = NSLog (dispatch_block_t ^{^{@ "No deadlock!"); CFStringRef retrievalue = dispatch_get_specific (& kQueueSpecific); if (retrievalue) {block (}else{); Dispatch_sync (queueC, block);}};});

So here’s a confirmation. Dispatch_set_target_queue (A, B) means that the priority of the A and B into the same level, then it will become a straight line running down.

Main points:
  • The behavior of the dispatch_get_current_queue function is often different from what the developer expects. This function is obsolete and should only be used when debugging.
  • Since the distribution queue is organized at a level, it is not possible to describe the concept of the current queue with a single queue object.
  • The dispatch_get_current_queue function is used to solve the deadlock caused by non reentrant code. However, the problem can be solved by using the sub function, usually can also change the queue specific data to solve.

The seventh chapter system framework

47 familiar with system framework

The meaning of the framework: a series of code into a dynamic library (dynamic), and in which the description of the interface into the header file, so that the things that come out of the framework. IOS slip construction using three party framework is a static library (static library), this is because the iOS application is not allowed in the library which contains dynamic. These things are strictly speaking not a real framework, however, all iOS platform system framework still uses dynamic library.

The development of “iOS application” with a graphical interface, will use a framework called Cocoa, or Cocoa Touch, but Cocoa itself is not a framework, which integrates a number but often used to create the application framework.

Developers will encounter the main framework is Foundation like NSObject, NSArray, NSDictionary and so on are among them.

There is also a Foundation companion framework called CoreFoundation. Technically, the CoreFoundation framework is not the Objective-C framework, an important framework but he has written a OC application should be familiar with the many functions in the Foundation framework, you can find the corresponding C language API in CoreFoundation. The CoreFoundation and Foundation frameworks are not only similar names, but also more closely linked, called “bridging” (toll-free).

Seamless bridging technology is implemented with some fairly complex code. The code allows the runtime system to view objects in the CoreFoundation framework as an ordinary Objective-C object.

  • CFNetwork: this framework provides C language level network communication capabilities.
  • CoreAudio:C language API to do audio hardware on the device.
  • CoreData: objects can be placed in the database for persistent storage.
  • AVFoundation: playback and record video audio.
  • CoreText: performs text typesetting and rendering operations.
    using C language to achieve the benefits of API is that you can bypass the OC operating system, thereby improving the speed of execution. Of course, because ARC is only responsible for the Objective-C object, so the use of these API need to pay attention to memory management issues. If it is the UI framework, the main is UIKit.

CoreAnimation is written in OC, CoreAnimation itself is not a framework, it is part of the QuartzCore framework. However, in the framework of the country, CoreAnimation is still a first-class citizen”.
CoreGraphics framework is written in C language. 2D rendering provides the necessary data structures and functions. Such as CGPoint, CGSize, CGRect, etc..

Main points:
  • Many system frameworks can be used directly, the most important of which is the Foundation and CoreFoundation, the two frameworks to build applications require many core functions.
  • Many common tasks can be done using a framework, such as audio processing, network communications, data management, etc..
  • Remember: the framework written in pure C is as important as the same as OC, and if you want to be a good OC developer, you should master the core concepts of C.

48 multi block enumeration, less for cycle

Relative to the For cycle corresponding to NSArray, NSDictionary, NSSet, NSEnumerator more convenient.
Dic: [aDictionary allKeys] assigned to NSArray;
Set: [aSet allObjects] assigned to NSArray;

NSEnumerator is an abstract class that provides two methods – nextObject and – allObjects


NSArray * anArray = "iSu" @[@ @ @ "Abner", "iSuAbner"]; NSEnumerator * enumerator = [anArray objectEnumerator]; ID iSuobject; while ((iSuobject = [enumerator nextObject])! = Nil) {NSLog (@ NSEnumerator save data% @ ", iSuobject);}


NSDictionary * aDictionary = "iSu" @{@: @ @ "1", "Abner", "2": @ @ @ "KoreaHappend": "3"}; NSEnumerator * DicEn = [aDictionary keyEnumerator]; ID key; while ((key = [DicEn nextObject])! = Nil) {ID value = aDictionary [key]; NSLog (@ NSDictionary% @ is corresponding,% @ "key, value);}


NSSet * aSet [NSSet setWithObjects:@ = "iSu", "Abner", "@ @ iSuAbner, nil]; NSEnumerator * SetEn = [aSet objectEnumerator]; ID Setobject; while ((Setobject = [SetEn nextObject])! = Nil) {NSLog (@ NSSet in the East West:% @", Setobject);}

Fast traverse:
is forin traversal:

NSDictionary: ID key; for (ID key in aDictionary ID) {value = aDictionary[key]; //NSLog (@ ForinNSDictionary% @ is corresponding,% @ "key, value);} NSSet: ID key; for (ID key in aDictionary (//NSLog) {@" ForinNSSet:%@ ", key);}

Block based traversal:

(void) enumerateObjectsUsingBlock: (void (^) (ID object, NSUInteger IDX, BOOL * stop)) block

The advantage of block traversal is that there is a pointer to the stop can selectively end the traversal.

[anArray enumerateObjectsUsingBlock:^ (ID / ergodic block _Nonnull obj, NSUInteger IDX, BOOL * _Nonnull stop if ([anArray[idx]) {isEqualToString:@ "Abner"]) {*stop = YES;}else{NSLog (@ block traversal:% @ ", anArray[idx]);}}];
Main points:
  • There are four ways to traverse the collection, the most basic way is the for cycle, followed by the NSEnumerator traversal method and fast traversal method, the latest and most advanced way is the block enumeration method”.
  • Block enumeration method itself can be executed by GCD concurrent execution of the traversal, without the need to write code. And other traversal method can not easily achieve this point.
  • If you know what the object of the collection to be traversed in advance, you should modify the block signature.

49 seamless connection to collection for custom memory management semantics

When can I use seamless connection?
I read the original text is basically a change in some of the base class memory management semantics.

For example, we need a NSDictionary key can be an copy object, we know that the numerical key normally is copied instead of saving, and if the key is not a compliance with the NSCopy object, then we need to keep him down, instead of copy.

First of all, say OC NSArray – > CFArrayRef

NSArray * anNSArray = @[@1, @2, @3, @4, @5]; / / __bridge is intended to: ARC still has the ownership of the OC object. __bridge_retained, by contrast, means that ARC surrender ownership of the object. --> __bridge CFArrayRef / / NSArray; aCFArray = CFArrayRef (__bridge CFArrayRef anNSArray); NSLog ("size array = of @%li, CFArrayGetCount (aCFArray));

Reverse CFArrayRef –> NSArray with __bridge_transfer

Here to remind you. If it is not from the C variable or array dictionary into OC, then need to be more than the variable parameters: / / CFArrayCreateMutable (< #CFAllocatorRef, allocator#> < #CFIndex capacity#> <, #const; CFArrayCallBacks *callBacks#> CFArrayCreate (<); #CFAllocatorRef allocator#> <, #const; void, **values#> < #CFIndex numValues#> < #const; CFArrayCallBacks, *callBacks#>); we use the change of the basic semantic memory management are variable, because you are not variable you have what semantic semantic change management. There... We use CFMutableDictionaryRef as the example requires four parameters: CFDictionaryCreateMutable (< #CFAllocatorRef, allocator#> < #CFIndex capacity#>, #const CFDictionaryKeyCallBacks *keyCallBacks#> <, < #const CFDictionaryValueCallBacks *valueCallBacks#>

The first is the memory, the second is a number, the third is the key attribute of the object memory management, the fourth parameter is the value attribute of the object memory management. Look carefully at the FortyNine demo.
last code:

CFMutableDictionaryRef aCFDictionary = CFDictionaryCreateMutable (NULL, 0, & keyCallbacks, & valueCallbacks); anNSDictionary (__bridge_transfer = NSMutableDictionary * NSMutableDictionary * aCFDictionary);

Such a dictionary can be generated to meet the health can not be copy object.

Main points:
  • Through seamless bridging count, you can switch back and forth between the Objective-C object in the Foundation framework and the C language structure in the CoreFoundation framework.
  • When you create a collection at the CoreFoundation level, you can specify a number of callback functions that indicate how the collection should handle its elements. Then, we can use seamless bridging technology to convert it into a special memory semantics Objective-C collection.

50 use NSCache instead of NSDictionary when building cache

Comparing the advantages of NSCache with respect to NSDictionary:
  1. When the system resources will be exhausted, it can automatically delete the cache, the dictionary will be more trouble, and NSCache will first delete the longest unused objects”.
    NSCache does not “copy” keys, but “keep” him, so that you can make health values can not be copy object.
  2. Developers can manipulate the cache to delete its contents. You can adjust the number of two, one is the total number of objects in the cache, and the second is the object of the total cost, the developer will be added to the cache object, you can specify the cost value”. When the total number of objects or overhead exceeds the upper limit, the cache may delete the object. When you want to add an object in the cache, you can only consider the use of this scale when you quickly calculate the “overhead value”. If the calculation process is not suitable for long. Specific examples can be seen Fifty.demo.
  3. There is a class NSPurgeableData, which is a subclass of NSMutableData, the object can be discarded at any time in accordance with the requirements of memory. We can through the NSDiscardableContent protocol in which he complied with the isContentDiscarded method to check whether the relevant memory has been released.
  4. If you want to access a NSPurgeableData object, you can call the beginContentAccess method, tell it should not be discarded after use now, call the endContentAccess method to tell when necessary can be discarded. This is similar to the reference count.
Main points:
  • NSCache should be used instead of NSDictionary when caching. Because NSCache can provide elegant automatic delete function, and is “thread safe”, in addition, it is different from the dictionary, and will not copy health.
  • You can set the upper limit to the NSCache object, the object in the cache to limit the total number and the total cost, and the scale is defined in the object cache to delete one time, but never put these dimensions as hard constraints and reliable “(hard limit), they only NSCache its guiding role.
  • The use of NSPurgeableData and NSCache can be used to automatically clear the data function, that is, when the NSPurgeableData object accounts for the system is discarded, the object itself will be removed from the cache.
  • If the cache is properly used, the response speed of the application can be improved. Only the kind of data that is “hard to calculate” is worth caching, such as those that need to be obtained from the network or read from the disk.

51 simplified initialize and load implementation code

The difference between load method and initialize method:

  1. The load method is called only once. Although initalize is only called once..
  2. The load method must run all load to continue, while the init is inert. Will not start directly.
  3. If the subclass does not implement the load method, the load method of the parent is not called.
    and initialize is normal, if the subclass does not achieve the realization of super class. If so, it is also necessary to implement the superclass.
  4. It is not safe to put other classes in a class’s load method, so it’s not clear whether the class is load.
Main points:
  • During the loading phase, if the class implements the load method, the system calls it. This method can also be defined in the class, the class load method than the first call in the classification. Unlike other methods, the load method does not participate in the overwrite mechanism.
  • Before you use a class for the first time, the system sends a initialize message to it. Since this method complies with the general override rules, it is often possible to determine which class to initialize.
  • Both load and init methods should be implemented in a little bit, which helps to keep the application’s response capability, as well as to reduce the chance of introducing a dependency loop
  • Global constants that cannot be set in the compiler can be initialized in the initialize method. A sentence:

    just to see my friend asked me what is the feeling of unrequited love, aware of the answer: like love toys in the store to buy, not enough money to save money, back to see time that prices, desperately saving money, so I think about the same time, back has been found was bought. I don’t want to see this toy in the trash, or I’ll pick it up.

52 don’t forget that NSTimer will retain its target

Timer is a very convenient and useful object, the Foundation framework has a class called NSTimer, developers can specify the absolute date and time, in order to perform tasks.
because the timer will retain its target object, the repeated execution of the task usually results in an application problem. For example:

- (void) startPolling{/ target because the object is self so the timer is held by self, while timer is a member of the self variable, so it retains the _pollTimer =[NSTimer scheduledTimerWithTimeInterval:5.0 target:self selector:@selector between userInfo:nil repeats:YES] (p_doPoll);}

To break the retention ring:
can only change the instance variable or make the timer invalid.
also said to call [_pollTimer invalidate]; _pollTime = nil; or change the instance variables.
unless all the code in your hands, otherwise we are not sure this method will be called timer failure, and even did not meet this condition, this by calling a method to avoid memory leaks, is not a good idea. Then we choose to change the instance variables.
create a NSTimer classifier, and then add a new class method

(NSTimer *) eoc_scheduledTimerWithTimeInterval: (NSTimeInterval) interval block: (void) (repeats) (repeats:) block (BOOL);

This code encapsulates the task performed by the timer into a “block”, which is passed as a userInfo parameter when the timer function is called. This parameter can be used to store the opacity value (i.e., the full value ID), as long as the timer is still valid, it will always retain it. When you pass a parameter, copy the block to the heap by the copy method, or it may not be valid until later. The timer target is now a NSTimer class object, is a single case, so whether the timer to keep him does not matter.
and block still have a strong reference cycle, this simple _ _weak on the line.

Main points:

  • The NSTimer object will retain its target until the timer itself fails. The invalidate method can be used to cause the counter to fail. In addition, a one-time timer will fail after the task is triggered.
  • The timer (repeating), which performs the task repeatedly, can be easily introduced into the retention ring. If the object of the timer retains the timer itself, it will certainly cause the retention ring. This ring may be a direct relationship, and may also be indirectly through other objects in the picture.
  • You can extend the functionality of NSTimer, with the “block” to break the retention ring. However, unless the NSTimer in the future provide the public interface function. Otherwise, you must create a classification, add the relevant code.


Write your own notes first is written in Pages, written in the book after Jane thought also left a layout, found that basically every point of the summary are not satisfied with their own, but also want to put up, feel what is chasing, ha ha, when the note is finished the word “2W”, the second time: the results found is 2.5W, which need to be improved or things too much, I hope my friends have what improvement proposal can tell me, I will always add this note, and then to change the code on GitHub.