[52 Effective ways to write high-quality iOS code] (11) System framework

Source: Internet
Author: User

[52 Effective ways to write high-quality iOS code] (11) System framework

Reference book: "Effective Objective-c 2.0", "English" Matt Galloway

Sneak Peek

47. Familiar with the system framework

48. Multi-use block enumeration, less use for loop

49. Use seamless bridging for containers that customize their memory management semantics

50. Use Nscache instead of nsdictionary when building cache

51. Streamlining the implementation code for initialize and load

52. Don't forget that Nstimer will keep its target object

Directory

    • 52 effective ways to write high-quality iOS Code 11 system Framework
      • Sneak Peek
      • Directory
      • 47th familiar with the system framework
      • 48th Multi-use block enumeration less use for loop
      • 49th use seamless bridging for containers that customize their memory management semantics
      • 50th Nscache instead of nsdictionary when building a cache
      • 51st simplified implementation code for initialize and load
      • 52nd, don't forget that Nstimer will keep its target object.

47th: Familiar with the system framework

Encapsulate a series of code as a dynamic library and put a header file that describes its interface, so that what you do is called the framework.

The main framework that developers encounter is the foundation, such as NSObject, Nsarray, Nsdictionary and others. The classes in the foundation framework use the NS prefix (representing the NeXTSTEP operating system, the basis of Mac OS X)

There is also a framework that accompanies the foundation, called Corefoundation. There are many C-language APIs that correspond to the functions in the foundation framework. The C language data structure in corefoundation can be bridged seamlessly with objective-c objects in the foundation framework.

In addition, there are the following common frameworks:

cfnetwork provides C language-level network communication capabilities

CoreAudio C language API for operating device audio hardware

avfoundation provides objective-c objects to return and record audio and video

coredata provides objective-c interface to put objects into the database for easy persistence

Coretext can efficiently perform typography and rendering operations with the C language interface

Appkit/uikit UI Framework for MAC OS X/ios applications

The framework written in pure C is as important as the objective-c, and if you want to be a good objective-c developer, you should master the core concepts of C language.

48th: Multi-use block enumeration, less use for loop

In programming, it is often necessary to enumerate the elements in the container, the current OBJECTIVE-C language has many ways to implement this function, first of all the old-fashioned for loop.

... */;for0; i < array.count; i++) {    id object = array[i];    ‘object‘... */;NSArray *keys = [dictionary allKeys];for0; i < keys.count; i++) {    id key = keys[i];    id value = dictionary[key];    ‘key‘‘value‘}

This is the most basic method, and therefore the function is very limited. Because both the dictionary and the set are unordered, traversing them requires an extra array to create (in this case, keys).

The second approach is to use the Nsenumerator abstract base class to traverse

... */;NSEnumerator *enumerator = [array objectEnumerator];id object;while ((object = [enumerator nextObject]) != nil) {        ‘object‘... */;NSEnumerator *enumerator = [dictionary keyEnumerator];id key;while ((key = [enumerator nextObject]) != nil) {    id value = dictionary[key];    ‘key‘‘value‘}

The advantage of this approach compared to the standard for loop is that the syntax is very similar regardless of which container is traversed, and the reverse enumerator can be obtained if a reverse traversal is required.

... */;NSEnumerator *enumerator = [array reverseObjectEnumerator];

OBJECTIVE-C 2.0 introduces a fast traversal. Similar to using Nsenumerator, and syntax is more concise, it starts the in keyword for the For loop.

... */;forin array){    ‘object‘... */;forin dictionary){    id value = dictionary[key];    ‘key‘‘value‘}

If an object of a class supports fast objects, you only need to adhere to the Nsfastenumeration protocol, which defines only one method:

- (NSUInteger)countByEnumeratingWithState:(NSFastEnumerarionState*)state object:(id*)stackbuffer count:(NSUInteger)length

Because Nsenumerator also implements the Nsfastenumeration protocol, the reverse traversal can be implemented as follows:

... */;forin [array reverseObjectEnumerator]){    ‘object‘}

This approach allows the class instance to return multiple objects at the same time, making the loop more efficient. However, there are two shortcomings, one is to traverse the dictionary can not get the keys and values at the same time, need more than one step, two, this method can not easily get the current traversal operation against the subscript (may be used).

The last method is block-based traversal, which is also the newest method

NSArray *array;[array enumerateObjectsUsingBlock:^(idBOOL *stop) {    // Do something with ‘object‘    if (shouldStop) {        YES;    }}];NSDictionary *dictionary;[dictionary enumerateKeysAndObjectsUsingBlock:^(ididBOOL *stop) {    // Do something with ‘key‘ and ‘value‘    if (shouldStop) {        YES;    }}];

The advantage of this approach is that you can get more information directly from the block while traversing, and you can avoid type conversion by modifying the method name of the block. If the object in the known dictionary must be a string:

*dictionary*key*obj*stop) {    //‘key‘and‘value‘}];

Of course, this method can also pass a selection mask to perform a reverse traversal

[array enumerateObjectsWithOptions:NSEnumerationReverse usingBlock:^(id obj, NSUInteger idx, BOOL *stop) {        Do something with ‘object‘    }];

In the options of the incoming nsenumerationconcurrent, can turn on the parallel execution function, through the underlying GCD to implement and processing.

49th: Use seamless bridging for containers that customize their memory management semantics

Seamless bridging enables the transformation of the data structures in the classes and corefoundation frameworks in the foundation framework. Here is a simple, seamless bridging:

*aNSArray@[@1,@2,@3];CFArrayRef aCFArray = (__bridge CFArrayRef)aNSArray;CFRelease(aCFArray);

There are 3 modifiers for converting operations:

// 不改变对象的原所有权// ARC交出对象的所有权,手动管理内存// ARC获得对象的所有权,自动管理内存

Objects that manage memory manually need to be reserved or freed with Cfretain and Cfrelease.

50th: Use Nscache instead of nsdictionary when building cache

When developing an iOS program, some programmers save images downloaded from the Internet in a dictionary, so that later use is not downloaded again, in fact, it is better to use the Nscache class, which is specifically designed to handle this task by the Foundation framework.

Nscache is better than nsdictionary in that it can automatically delete the longest unused cache when system resources are going to be exhausted. Nscache does not copy the key, but retains it, which is more convenient when the key does not support copy operation. In addition Nscache is thread-safe, without the need to write the lock code, multiple threads can also access the Nscache.

Here is the usage of the cache

#import <Foundation/Foundation.h> //Network Data acquisition classtypedef void(^eocnetworkfetchercompletionhandler) (NSData *data); @interface eocnetworkfetcher : nsobject - (ID) Initwithurl: (Nsurl*) url;-(void) Startwithcompletionhandler: (Eocnetworkfetchercompletionhandler) handler;@end//classes using the capture and caching results @interface eocclass : nsobject @end @implementation eocclass{Nscache *_cache;} - (ID) init{if(( Self= [SuperInit]) {_cache = [nscache new];//Set the cache to a maximum of 100 objects with a total overhead of 5MB_cache. Countlimit= -; _cache. Totalcostlimit=5*1024x768*1024x768; }return  Self;} - (void) Downloaddataforurl: (Nsurl*) url{//Nspurgeabledata is a subclass of Nsmutabledata, with a reference count similar to memory management, when the reference count is 0 o'clock, the memory occupied by the object can be discarded as needed at any timeNspurgeabledata *cachedata = [_cache Objectforkey:url];if(CacheData) {//Cache hit        //reference count +1[CacheData begincontentaccess];//Using cached data[ SelfUsedata:cachedata];//reference count-1[CacheData endcontentaccess]; }Else{//Cache missesEocnetworkfetcher *fetcher = [[Eocnetworkfetcher alloc] initwithurl:url]; [Fetcher startwithcompletionhandler:^ (NSData *data) {//Create Nspurgeabledata object, reference count +1Nspurgeabledata *purgeabledata = [Nspurgeabledata datawithdata:data]; [_cache setobject:purgeabledata Forkey:url Cost:purgeabledata. Length];//Using cached data[ SelfUsedata:cachedata];//reference count-1[Purgeabledata endcontentaccess];    }]; }}@end
51st: Streamlining the implementation code for initialize and load

Sometimes a class must perform certain initialization operations before it can be used properly. In Objective-c, most classes inherit from the root class of NSObject, and the class has two methods that can be used to implement this initialization. The first is the Load method:

+ (void)load

The

joins each class and classification in the runtime system, calls this method, and is called only once. In iOS, such methods are executed when the application starts (dynamic loading can be used in Mac OS x and then loaded after the program is started). When the Load method is executed, the load method of the superclass is executed first, and then the subclass is executed, and then the class is executed. If your code also relies on other libraries, you will have limited execution of the Load method in that library. However, in a given library, the loading order of each class cannot be determined.

#import <Foundation/Foundation.h>#import "EOCClassA.h" // 来自同一个库@interface EOCClassB : NSObject@end@implementation EOCClassB+ (void)load{    NSLog(@"Loading EOCClassB");    EOCClassA *object = [EOCClassA new];    // ues object}@end

This code is unsafe because it is not possible to determine that Eocclassa is already loaded when the EOCCLASSB load method is executed.

The Load method does not follow the inheritance rules of the normal method, and if a class does not implement the Load method itself, the system will not invoke it regardless of whether its superclass implements this method.

The Load method should be as concise as possible because the entire program will block when it executes the load method. Do not wait for the lock inside, and do not invoke methods that may lock. In short, do not do things you can not do.

To perform initialization operations related to classes, there is another way to override the following methods

+ (void)initialize

For each class, the method is called before the program first calls the class, and is called only once. There are 3 main differences between the Initialize and the Load method:
1. The Initialize method is called only if the program uses the relevant classes, and load is different, the program must block and wait for all classes of load to execute before continuing.
2. When the runtime system executes the Initialize method, it is in a normal state, not a blocking state. To ensure thread safety, only the other threads that operate the class or class instance are blocked.
3. If a class does not implement the Initialize method, and the superclass implements it, then the method of the superclass is run.

The Initialize method should also be as concise as possible, only need to set some state inside, so that the class can function properly, do not do that time-consuming or need to lock the task, and try not to invoke other methods in it, even the method of this class.

If a global state cannot be initialized at compile time, it can be placed in initialize.

//EOCClass.h#import <Foundation/Foundation.h>  @interface eocclass : nsobject @end//EOCCLASS.M#import "EOCClass.h" Static Const intKinterval =Ten;Static Nsmutablearray*ksomeobjects; @implementation eocclass + (void) initialize{//Determine the type of class to prevent execution in subclasses    if( Self= = [Eocclass class]) {ksomeobjects = [NsmutablearrayNEW]; }}@end

Integers can be defined at compile time, but mutable arrays do not, so creating an object below will cause an error.

staticNSMutableArray *kSomeObjects = [NSMutableArray new];
52nd: Don't forget Nstimer will keep its target object

The Nstimer (timer) is a very handy and useful object, and the timer is associated with the run loop, and the running loop will trigger the task. Only when the timer is placed in the running loop can it trigger the task normally. For example, the following method can create a timer and pre-schedule it in the current run loop:

+ (NSTimer *)scheduledTimerWithTimeInterval:(NSTimeInterval)titarget:(id)aTargetselector:(SEL)aSelectoruserInfo:(id)userInforepeats:(BOOL)yesOrNo;

The timer created by this method executes the task after the specified interval. You can also make it perform tasks repeatedly until the developer manually closes it later. Target and selector indicate which method is called on which object. Once the task is completed, the one-time timer fails, and if repeats is yes, the Invalidate method must be called to stop it.

A timer for repeating patterns, it is easy to introduce a retention ring:

 @interface eocclass : nsobject - (void) startpolling;-(void) stoppolling;@end @implementation eocclass{Nstimer *_politimer;} - (ID) init{return[SuperINIT];} - (void) dealloc{[_politimer invalidate];} - (void) stoppolling{[_politimer invalidate]; _politimer =Nil;} - (void) startpolling{_politimer = [Nstimer scheduledtimerwithtimeinterval:5.0Target SelfSelector@selector(P_dopoll) UserInfo:NilRepeatsYES];} - (void) p_dopoll{//Code}

If you create an instance of this class and call the Startpolling method. When creating a timer, keep this instance because the target object is self. However, because the timer is stored with an instance variable, the instance also retains the counter, resulting in a retention ring.

Calling the Stoppolling method or making the system recycle the instance (which automatically calls the Dealloc method) can invalidate the timer, breaking the loop, but not ensuring that the Startpolling method is called, and that the instance is never reclaimed by the system because the timer holds the instance. When the last external reference of the Eocclass instance is moved, the instance remains alive, and the timer object is not possible to be reclaimed by the system, except that there is no other reference outside the timer to point to the instance, and the instance is lost forever, causing a memory leak.

The solution is to use blocks to add new features to the timer

 @interface nstimer (eocblockssupport)+ (nstimer*) Eoc_scheduledtimerwithtimeinterval: (Nstimeinterval) Interval BLOCK: (void(^) ()) Block repeats: (BOOL) repeats;@end @implementation nstimer( eocblockssupport)+ (nstimer*) Eoc_scheduledtimerwithtimeinterval: (Nstimeinterval) Interval BLOCK: (void(^) ()) Block repeats: (BOOL) repeats{return[ SelfScheduledtimerwithtimeinterval:interval Target: SelfSelector@selector(eoc_blockinvoke:) userinfo:[block copy] repeats:repeats];} + (void) Eoc_blockinvoke: (nstimer*) timer{void(^block) () = Timer. UserInfo;if(block)    {block (); }}

Then modify the Stoppolling method:

- (void)startPolling{    __weakself;    _poliTimer = [NSTimer eoc_scheduledTimerWithTimeInterval:5.0 block:^{        EOCClass *strongSelf = weakSelf;        [strongSelf p_doPoll];    } repeats:YES];}

This code first defines a weak reference to self and then captures the reference with a block so that self is not retained by the timer, and immediately generates a strong reference when the block starts executing, ensuring that the instance continues to survive in the executor.

[52 Effective ways to write high-quality iOS code] (11) System framework

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.