[52 Effective ways to write high-quality iOS code] (i) OBJECTIVE-C Foundation

Source: Internet
Author: User
Tags uikit

[52 Effective ways to write high-quality iOS code] (i) OBJECTIVE-C Foundation

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

Sneak Peek

1. Understanding the origins of the Objective-c language
2. Introduce as few other header files as possible in the header file of the class
3. Multi-use literal syntax, less use of the equivalent method
4. Multi-use type constants, less # define preprocessor directives
5. Using enumerations to represent States, options, status codes

Directory

    • 52 effective ways to write high-quality iOS code a OBJECTIVE-C foundation
      • Sneak Peek
      • Directory
      • 1th understand the origin of objective-c language
      • 2nd Minimize the introduction of other header files in the header file of the class
      • 3rd method of using more literal syntax less than the equivalent
      • 4th multiple-use type constants less with define preprocessor directives
      • 5th the Status Option status code is represented by an enumeration

1th: Understanding the origins of Objective-c language

The difference between an object-oriented language such as Objective-c and C++,java is that OBJECTIVE-C uses "message structure" rather than "function call." Objective-c language is evolved by the originator Smalltalk of the message-type language.

Syntax differences between a message and a function call:

// 消息(Objective-C)Object *obj = [Objectnew];[obj performWith:parameter1 and:parameter2];// 函数调用(C++)ObjectnewObject;obj->perform(parameter1,parameter2);

The key difference is that, using the language of the message structure, the code that the runtime should execute is determined by the runtime environment, and the language used by the function call is determined by the compiler. The important work of objective-c is done by the runtime component, not the compiler.

Objective-c is a superset of C, so all the features in C are still applicable when writing objective-c code. Understanding the memory model of the C language is particularly important, which helps to understand how the OBJECTIVE-C memory model and its reference counting mechanism work. The pointer in the Objective-c language is used to indicate the object. To declare a variable, it refers to an object:

NSString *someString = @"the string";NSString *anotherString = someString;

Two variables are pointers to nsstring. All objects of the Objective-c language must be declared this way, because the object's memory is always allocated in the heap, not in the stack. The Objective-c object is not allocated on the stack. The memory of the two variables is allocated on the stack, and the same value in both memory is the memory address of the NSString object.

The memory allocated in the heap must be managed directly, and the memory allocated in the stack to hold the variable is automatically cleaned up when its stack frame pops up.

In objective-c code, there are sometimes variables that do not contain * in the definition, and they may use stack space, for example:

CGRect frame;

CGRect is a C struct, and the entire system framework uses this structure. If you use the Objective-c object instead, you need additional overhead, such as allocating and freeing heap memory. If you only want to save non-object types such as int, float, double, char, and so on, you usually use the cgrect structure.

2nd: Minimize the introduction of other header files in the class header file

Like C and C + +, Objective-c also uses header files and implementation files to partition code.

Create a Eocperson class and use another class in the class to eocemployer an instance of the class

//EOCPerson.h#import <Foundation/Foundation.h>  @class eocemployer; @interface eocperson : nsobject @property(nonatomic, copy)NSString*firstname;@property(nonatomic, copy)NSString*lastname;@property(nonatomic,Strong) Eocemployer *employer;@end//EOCPERSON.M#import "EOCPerson.h" #import "EOCEmployer.h"  @implementation eocperson //Implementation Method@end

Using a statement in a header file @class EOCEmployer; tells the compiler to use this class, without having to know all the details of the class, and then #import "EOCEmployer.h" introducing the Eocemployer class into the implementation file that needs to know all of its interface details. This practice is called forward declaration. If EOCEmployer.h is introduced directly into the header file, all of the content in the EOCEmployer.h is introduced, and the process continues to introduce many things that are not available at all, increase compilation time, and may cause circular references.

However, there are times when you cannot use forward declarations, such as a custom class that inherits from a superclass or conforms to a protocol.

//EOCRectangle.h  Span class= "Hljs-preprocessor" > #import  "EOCShape.h"    #import " EOCDrawable.h "   @interface  eocrectangle :  Eocshape  <eocdrawable ;   @property  (nonatomic , assign ) float  width;  @property  (nonatomic , assign ) float  height;  @end   

If a custom class inherits from a superclass, you must introduce a header file that defines that superclass, and if you want to comply with a protocol, try to move the class to the classification (what is a classification?) according to the Declaration of a Protocol. In If not, put the protocol in a single header file and introduce it.

3rd: More use of literal grammar, less use of the equivalent of the method

The declaration of instances of the 4 classes of NSString, NSNumber, Nsarray, nsdictionary in the foundation framework can be declared using common Alloc and Init methods, or directly using literal syntax:

//block integers, floating-point numbers into the Objective-c object, either by literal or by calling methods in NSNumber. //literalNSNumber*intnumber = @1;//Equivalence methodNSNumber*intnumber = [NSNumberNumberwithint:1];//literalNSNumber*doublenumber = @3.14159//Equivalence methodNSNumber*doublenumber = [NSNumberNumberwithdouble:3.14159];//Literal syntax also applies to expressionsintx =5;floaty =6.32FNSNumber*expressionnumber = @ (x * y);
//use method and literal syntax to create an array  Span class= "hljs-built_in" >nsarray  *animals = [nsarray  arraywithobjects:@  "cat" , @ "dog" , @ " Mouse ", nil ]; nsarray  *animals = @[@ "cat" , @" "Dog" , @ "mouse" ]; //use method and literal syntax to get the object corresponding to the subscript  nsstring  *dog = [Animals objectatindex:1 ];< Span class= "hljs-built_in" >nsstring  *dog = Animals[1 ];  

The benefit of using the literal: If you create an array with 3 objects, the second object is nil, the other two objects are valid, and if created with literal syntax, an exception will be thrown at run time to find the error faster. If you use the Arraywithobjects: method, the exception is not thrown, but the created array contains only the first object, because the method processes each parameter in turn until nil is found. This can lead to errors that are not easily detected.

//Use method and literal syntax to create a dictionarynsdictionary*persondata = [nsdictionarydictionarywithobjectandkeys:@"Matt.",@"FirstName",@"Galloway",@"LastName",[NSNumberNumberwithint: -],@"Age",Nil];nsdictionary*persondata = @{@"FirstName":@"Matt.",@"LastName":@"Galloway",@"Age":@ -};//Use method and literal syntax to get the object corresponding to the subscriptNSString*lastname = [Persondata objectforkey:@"LastName"];NSString*lastname = persondata[@"LastName"];

Creating a dictionary with literal syntax also has a similar advantage, which can help with error checking.

strings, arrays, and dictionary objects created using the literal syntax are immutable. If you want a variable version of an object, you need to copy it.

*mutable = [@[@1,@2,@3] mutableCopy];

This will call a method more than one, and you will need to create an object again, but using literal syntax can outweigh the disadvantages.

4th: Multi-use type constants, less # define preprocessor directives

Constants are often defined when writing code, for example, to write a UI view class that shows the animation and then disappears. If you want to extract the time to play the animation as a constant, this is usually the case:

#define ANIMATION_DURATION 0.3

However, the defined constants do not have type information, and the preprocessing process will replace the encountered Animation_duration to 0.3, assuming that the directive is declared in a header file, then all the code that introduces the header file will be replaced. A better way is to define a constant of type Nstimeinterval

//EOCAnimatedView.h  Span class= "Hljs-preprocessor" > #import <UIKIT/UIKIT.H>    @interface  eocanimatedview : uiview    @end  // EOCANIMATEDVIEW.M   #import  "EOCAnimatedView.h"   //Declaration definition constants  static  const  nstimeinterval  eocanimationduration = 0.3 ;  @implementation   Eocanimatedview    @end   

Variables must be declared with static and const at the same time. The const modifier can protect a variable from being modified. The static modifier means that only the compilation unit that defines this variable is visible. If you do not add static, a variable with the same name is declared in another compilation unit and an error is made. The constants created in this way are not public.

If you need to expose a constant externally, you need to place the constant in the global symbol table so that you can use it outside the compilation unit that defines the constant:

//EOCAnimatedView.h#import <UIKit/UIKit.h> //Declare Constantsextern Const NstimeintervalEocanimationduration; @interface eocanimatedview : UIView @end//EOCANIMATEDVIEW.M#import "EOCAnimatedView.h" //Define ConstantsConst NstimeintervalEocanimationduration =0.3; @implementation eocanimatedview @end

Such constants must be defined and can be defined only once. Because you want to put it in the global symbol table, you need to be careful about naming constants to avoid name collisions.

5th: Use enumerations to represent States, options, status codes

An enumeration is a constant naming method. The various states that an object undergoes can be defined as a simple set of enumerations:

// 套接字连接状态enumEOCConnectionState{    EOCConnectionStateDisconnected,    EOCConnectionStateConnecting,    EOCConnectionStateConnected,};

The compiler assigns each enumeration value a unique number, starting with 0 and incrementing by 1 for each enumeration. The data type used to implement the enumeration depends on the compiler, but the number of bits (bit) must be fully represented under the enumeration number.

The C++11 standard extends the features of enumerations, and objective-c also benefits from the C++11 standard. One of the changes is that you can indicate which underlying data type is used to hold variables of the enumerated type. The advantage of this is that you can declare the enumeration variables forward.

// 指定底层数据类型enumNSInteger {/* . . . */};// 向前声明枚举变量enumNSInteger;// 手动指定枚举成员的值,接下来的枚举值都会在上一个的基础上自动递增1enum EOCConnectionState{    1,    EOCConnectionStateConnecting,    EOCConnectionStateConnected,};

There is also a situation where enumeration types should be used, which is when defining options. This is especially true if these options can be combined with each other:

//device support direction   Enum  eocpermitteddirection{eocpermitteddirectionup = 1  << 0 , //0001 on  eocpermitteddirectiondown = 1  << 1 , //0010 under  Eocpermitteddirectionleft = 1  << 2 , //0100 left  eocpermitteddirectionright = 1  << 3 , //1000 Right }; //Direction enumeration value of 0101, indicating support for upper and left two orientations  enum  Eocpermitteddirection Direction = eocpermitteddirectionup| Eocpermitteddirectionleft;  

Create enumeration types using macros (both Ns_enum and ns_options are the secondary macros defined in the foundation framework)

// 普通枚举类型typedef NS_ENUM(NSUInteger, EOCConnectionState){    1,    EOCConnectionStateConnecting,    EOCConnectionStateConnected,};// 选项枚举类型typedef NS_OPTIONS(NSUInteger, EOCPermittedDirection){    10,    11,    12,    13,};

Use enumerations in the switch statement:

typedef NS_ENUM(NSUInteger, EOCConnectionState){    EOCConnectionStateDisconnected,    EOCConnectionStateConnecting,    EOCConnectionStateConnected,};EOCConnectionState state = EOCConnectionStateConnected;switch (state) {    case EOCConnectionStateDisconnected:        // Handle disconnected state        break;    case EOCConnectionStateConnecting:        // Handle connecting state        break;    case EOCConnectionStateConnected:        // Handle connected state        break;}

When using enumerations in a switch statement, it is best not to have the default branch, and if a new state is added to the enumeration, the compiler warns that the state is not handled in the switch statement, and if the default branch is written, it will cause the compiler not to issue a warning message. It is common to ensure that all enumeration values are handled correctly by the switch statement.

[52 Effective ways to write high-quality iOS code] (i) OBJECTIVE-C Foundation

Related Article

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.