An Effective Method for writing high-quality OC code and writing high-quality oc code

Source: Internet
Author: User
Tags notification center

An Effective Method for writing high-quality OC code and writing high-quality oc code
1. Write this file only for your own memory, and there are related PDF files. If you need to leave a mailbox .. 2. Try to introduce as few header files as possible in Class header files.

  • Do not introduce header files unless necessary. In general, you should use the Forward Declaration in the header file of a class to mention other classes (use @ class), and introduce the header files of those classes in the implementation file, in this way, the coupling between classes can be minimized.
  • If you want to declare that a class complies with a certain protocol, you should put the protocol in the classification, or separately put the Protocol in a header file, and then introduce it.
3. Use more literal syntax and less equivalent methods.

The following is a comparison of the two methods:

// Example of using literal syntax NSArray * array1 = @ [@ "1", @ "2"]; NSNumber * number1 = @ 1; NSDictionary * dictionary1 = @ {@ "key": @ "value"}; // use the corresponding method NSArray * array2 = [NSArray arrayWithObjects: @ "1 ", @ "2", nil]; NSNumber * number2 = [NSNumber numberWithInt: 2]; NSDictionary * dictionary2 = [NSDictionary dictionaryWithWithObjectsAndKeys: @ "value": @ "key"];
  • Use the literal syntax to create strings, values, arrays, and dictionaries. Compared with conventional methods
  • The subscript operation should be used to access the elements corresponding to the array subscript or dictionary key.
  • When using the literal syntax to create an array or dictionary, if the value contains nil, an exception is thrown. Therefore, make sure that the value does not contain nil.
4. Multi-purpose type constants, less use # define preprocessing commands

Method for defining a constant:

// Type 1: preprocessing command # define ANIMATION_DURATION 0.3 // type 2: static constant static const NSTimeInterval kAnimationDuration = 0.3

We generally recommend the second method. constants defined in this method contain type information, which helps you read the code.

Note: The constant naming method is: if a constant is limited to a "compilation unit" (that is, an implementation file ,. m file), then add the letter k in front; if the constant is visible outside the class, it is usually prefix with the class name.

If we need to publish a constant, we can write the following code:

// Test.h#import <Foundation/Foundation.h>extern NSString *const TestDidChangeNotification;@interface Test : NSObject@end// Test.m#import "Test.h"NSString *const TestDidChangeNotification = @"TestDidChangeNotification";@implementation Test
  • Do not use preprocessing commands to define constants. The defined constant does not contain the type information. The compiler searches for and replaces the constant based on this variable before compilation. Even if a constant value is redefined, the compiler does not warn that the constant values in the application are inconsistent.
  • Use static const in the. m file to define the "visible constants in the compilation unit", without adding the class name prefix and k
  • Use extern in the header file to declare a global constant and define its value in the relevant implementation file. This constant must be prefixed with the class name.
5. Use enumeration to indicate the status, options, and status code.
  • Enumeration is used to indicate the state of the state machine, the options passed to the method, and the State Code Equivalent. Give these values an easy-to-understand name.
  • Use the NS_ENUM and NS_OPTIONS macros to define enumeration types and specify their underlying data types.
  • Do not default the branch in advance in the switch statement that processes enumeration types. In this way, after the new enumeration is added, the compiler will prompt the developer that the switch statement does not process all Enumeration
6. understand the concept of "attribute"
  • Use the @ property syntax to define the data encapsulated in the object
  • Use the "traits" attribute keyword to specify the correct semantics required for data storage
  • When setting the instance variables corresponding to an attribute, you must follow the semantics declared by this attribute.
7. Try to directly access instance variables within the object

For example, the Person class has a name attribute. When we want to obtain data for this name attribute within this class, one is through self. name, and the other is _ name.

The two differences:

  • Direct access to instance variables is faster. The code generated by the compiler directly accesses the memory that saves the instance variables of the object.
  • Directly accessing instance variables does not call its "setting method", which bypasses the "Memory Management Semantics" defined for the relevant attributes. For example, directly access an attribute declared as copy under ARC. This attribute will not be copied, but new values will be retained and old values will be released.
  • If you directly access the instance variables, "KVO" is not triggered. Whether the problem occurs depends on the specific object behavior.
  • Attribute-based access helps you troubleshoot related errors, because you can add a breakpoint to the "get method" or "Set Method" to monitor the caller of this attribute and the access time.

Note:

  • When reading data inside an object, you should read data directly through instance variables. When writing data, you should write data through attributes.
  • In the initialization method and dealloc method, data should always be read and written directly through instance variables.
  • Sometimes a data is configured using the inert initialization technology. In this case, data needs to be read through attributes.
8. Understand the concept of "object equivalence"
  • To detect the equality of objects, provide the "isEqual:" And hash methods.
  • The same object must have the same hash code, but the two objects with the same hash code may not be the same.
  • Do not blindly inspect each attribute one by one, but specify a scheme based on specific requirements.
9. Hide implementation details in the class family mode

"Class family" is a very good mode that can hide the implementation details behind the "abstract base class. This mode is widely used in the system framework of OC. For example, if there is a class that handles employees, each employee has two attributes: "name" and "salary, managers can execute their daily work, but the work content of various employees is different. When a manager leads an employee to do a project, there is no need to know how to complete the specific work, you only need to instruct it to start work. We reconstruct multiple child classes and implement the methods for each person to complete specific work in the Child classes.

First, define an abstract base class:

Typedef NS_ENUM (NSUInteger, EOCEmployeeType) {average, minimum, minimum} @ interface EOCEmployee: NSObject @ property (copy, nonatomic) NSString * name; @ property (assign, nonatomic) NSInteger salary; // create an employee object + (EOCEmployee *) employeeWithType :( EOCEmployeeType) type; // Let the employee work-(void) doADaysWork; @ implementation EOCEmployee + (EOCEmployee *) employeeWithType :( partial) type {switch (type) {case EOCEmployeeTypeDeveloper: return [EOCEmployeeTypeDeveloper new]; break; case when: return [new]; break; case EOCEmployeeTypeDeveloper: return [new]; break;}-(void) doADayWork {// subclass Implementation} @ end

Then, each "entity subclass" is inherited from the base class, for example:

@interface EOCEmployeeDeveloper : EOCEmployee@end@implementation EOCEmployeeDeveloper- (void)doADaysWork{   [self wirteCode];}@end

In this example, the base class implements a "class method", which allocates corresponding employee class instances according to the employee category to be created, this "factory mode" is one of the ways to create a class family.

If the class to which the object belongs is located in a class family, you may feel that you have created an instance of a class. However, you actually created an instance of its subclass.

NSNumber and NSArray in OC are all class families.

  • The class-family mode hides implementation details behind a simple set of public interfaces.
  • Class families are often used in the system framework.
  • Be careful when integrating child classes from the common abstract base classes of the class family. Read the development documents first.
10. Use Associated objects in existing classes to store Custom Data

Sometimes we need to store relevant information in the object. At this time, we usually inherit a subclass from the class to which the object belongs, and then use this subclass object instead, however, sometimes a class instance may be created by a mechanism, and developers cannot make this mechanism create a subclass instance they write. One of the powerful features of OC can be solved, that is, "correlated objects ".

It is implemented based on runtime.

  • Two objects can be connected through the "correlated object" mechanism.
  • You can specify the memory management semantics when defining the correlated object to mimic the "ownership" and "non-use" used when defining the attribute"
  • Associated objects should be selected only when other approaches are not feasible. This approach usually introduces bugs that are difficult to find.
11. Understand the role of objc_msgSend

Calling methods on objects is a frequently used function in OC. The term is "passing messages ". The message has a "name" or "Select Sub", which can accept parameters and may return values.

The C language uses "static binding" to determine the function to be called during compilation.

When "dynamic binding" is used in OC, after an object receives a message, the method to be called is completely determined at runtime, and can even be changed when the program is running.

Here we will not explain the use of objc_msgSend. If you need it, you can refer to the use of runtime.

The objc_msgSend function calls an appropriate method based on the receiver and the sub-type selected. To complete this operation, the method needs to find its "method list" in the class to which the receiver belongs ", if you can find the method that matches the selected sub-name, jump to its implementation code. If you cannot find the method, search for it along the inheritance system. If not, then, the message is forwarded. Each class will have a cache to cache the method. If the class is sent to the same message as the selected sub-class later, the execution will be very fast.

  • A Message consists of a receiver, a subscriber, and a parameter. Sending a message to an object is equivalent to calling a method on the object"
  • All messages sent to an object must be processed by the "dynamic message dispatching system". The system will find the corresponding method and execute its code.
12. Understand the message forwarding mechanism

When an object receives messages that cannot be interpreted, it starts the "message forwarding" mechanism, through which the programmer can tell the object how to process unknown messages.

If unrecognized selector sent to instance 0x87 is displayed on the console, it indicates that you have sent a message to an object that cannot be interpreted, and thus enabled the message forwarding mechanism, then it ends with a program crash.

Message Forwarding is divided into two phases:

Dynamic Method Analysis:

After an object receives a message that cannot be interpreted, it first calls the following class methods of its class:

// If this class calls an unimplemented instance method, this method is called
+ (BOOL) resolveInstanceMethod :( SEL) selector
// If this class calls an unimplemented class method, this method is called.
+ (BOOL) resolveClassMethod;

The parameter of this method is the unknown selector. Its return value is of the Boolean type, indicating whether this class can add an instance method to process this selector. Before continuing to execute the forwarding mechanism, we can use runtime to dynamically add this method.

The premise for using this method is that the implementation code of the relevant method has been written, and it is enough to dynamically insert it into the class when running.

Alternate receiver:

The current recipient has a second chance to process the unknown selector. In this step, the runtime system will ask whether the message can be transferred to other recipients for processing:

// The method parameter indicates an unknown selector. If the current receiver can find the secondary object, it will return it. If it cannot find the secondary object, it will return nil. -(Id) forwardingTargetForSelector :( SEL) selector;

We can use "Combination" to simulate some features of "Multi-inheritance". Within an object, there may be a series of other objects, this method can be used to process the returned internal objects of a selected sub-object. In this way, it seems that the object is handled by itself.

Complete Message forwarding:

If forwarding has come to this step, the only thing you can do is to enable the complete message forwarding mechanism. The system will create an NSInvocation object, encapsulate all the details related to the unprocessed message. This object includes the Selection Sub-, target (target), and parameters. When an NSInvocation object is triggered, the "message dispatching system" will launch the task and assign the message to the target object.

In this step, the following methods are called to forward messages:

// This method can be implemented very easily. You only need to change the call target so that the message can be called on the new target, however, the method implemented in this way is equivalent to the method implemented in the "backup receiver" solution, so few people use this simple implementation method. The more useful implementation method is: before sending a message, change the message content in some way, such as appending another parameter or changing the selection sub-item. -(Void) forwardInvocation :( NSInvocation *) invocation;

When this method is implemented, if you find that a call operation should not be processed by this class, you need to call the method with the same name as the super class. In this way, each class in the inheritance system has the opportunity to process the call request until NSObject. If the NSObject class method is called at last, the method will continue to call "doesNotRecognizeSelector ", to throw an exception. This exception indicates that the sub-account cannot be processed.

The entire process of message forwarding:

The receiver has the opportunity to process messages in each step. The more the next step, the higher the message processing cost. It is best to finish the first step. In this case, the system can cache this method at runtime. If the instance of this class receives the sub-selection with the same name later, the message forwarding process does not need to be started. If you want to forward the message to the receiver in step 3, it is better to forward the forwarding operation to step 2. Because the third step only modifies the call target, it is easier to put this change in the second step. Otherwise, you have to create and process the complete NSInvocation.

  • If the object cannot respond to a selection subitem, it enters the message forwarding process.
  • Through the dynamic method parsing function at runtime, we can add a method to the class when it is needed.
  • Objects that cannot be interpreted can be transferred to other objects for processing.
  • After the two steps above, if there is still no way to select Sub-nodes, the complete message forwarding mechanism will be enabled.

Example of http://www.cocoachina.com/ios/20150604/12013.html-related

13. Use "method allocation technology" to debug the "black box method"

This mainly refers to the method exchange of runtime. runtime can be seen in the introduction to runtime in the OC category.

Here is a simple analysis:

The method list of the class maps the sub-names to the corresponding method implementation, so that the "dynamic message distribution system" can find the method to be called accordingly, these methods are expressed in the form of function pointers. These pointers are called IMP, and their prototype is as follows:

Id (* IMP) (id, SEL ,...)

For example, the NSString class can select child corresponding to lowercaseString, uppercaseString, and capitalizedString. Each selection child in this ing table is mapped to a different IMP:

Several methods provided by the system during the OC runtime can be used to operate this table. developers can add a selection sub to it, or change the method implementation corresponding to a selection sub, you can also swap two pointers mapped to the Selection Sub-databases. For example, if we swap the lowercaseString and uppercaseString methods, the method table of the class will look like the following:

In the new ing table, we can see that the lowercaseString and uppercaseString methods are implemented, and a selection sub named newSelector is added. No subclass is required for the above modification, if you modify the layout of the "method table", It will be reflected on all NSString instances in the program.

With this solution, developers can add the logging function for those black box methods that do not know their specific implementations, which is helpful for program debugging.

  • During the runtime, you can add or replace the method implementation corresponding to the sub-selection in the class.
  • Use another implementation to replace the original method implementation. This process is called "method allocation", that is, method exchange. Developers often use this technology to add new features to the original implementation.
  • Generally, modification methods must be implemented at runtime only when the program is debugged. This method should not be abused.
14. Understand the intention of "Class Object"

The object type is not bound during compilation, but needs to be searched at runtime. In addition, there is a special class called id, which can refer to any OC object type. Generally, it should specify the specific type of the Message Receiver. In this case, if a message cannot be interpreted is sent to it, the compiler generates a warning message, and an object of the id type is not, the compiler determines that it can respond to all messages.

"View object types at runtime" is also called "type information query" (introspection). This powerful and useful feature is built into the NSObject protocol of the Foundation framework, all objects inherited from the common root class must comply with this Protocol. Do not directly compare the class to which the object belongs in the program. It is wise to call the "type information query method ".

Before that, let's take a look at the nature of the OC object?

Each OC object instance is a pointer to a certain block of memory data. Therefore, when declaring a variable, the type must be followed by a "*" character, as shown below:

// PointerVariable can be understood as a variable that stores the memory address, and the data of NSString itself is stored in that address. Therefore, it can be said that the variable "points to" NSString instance. This applies to all OC objects. NSString * pointerVariable = @ "Some string ";

The data structure used to describe the OC object is defined in the header file of the Runtime Library. The id type is also defined here:

typedef struct objc_object{    Class isa;}*id;

For each object, the first member of the struct is a variable of the Class. This variable defines the class to which the object belongs, usually called the "is a" pointer. For example, all objects in the preceding example are "is a" (is a) NSString, therefore, its "is a" Pointer Points to NSString. The Class object is also defined in the header file of the Runtime Library:

typedef stuct objc_class *Class;struct objc_class{    Class isa;    Class super_class;    const char *name;    long version;    long info;    long instance_size;    struct objc_ivar_list *ivars;    struct objc_method_list *methodList;    struct objc_cache *cache;    struct objc_protocol_list *protocols;}

This struct stores the "metadata" of the class. For example, the class instance implements several methods, including how many instance variables are available. The first variable of this struct is also the isa pointer, which indicates that the Class itself is also an OC object. The struct also has a variable super_class, which defines the superclass of this class. The type to which the Class Object belongs (that is, the type pointed by the isa pointer) is another class called "Meta class", which is used to express the metadata of the Class Object. "Class methods" are defined here, because these methods can be understood as the instance methods of class objects. Each class has only one "Class Object", and each "Class Object" has only one "Meta class" related to it ".

The super_class pointer establishes an inheritance relationship, while the isa pointer describes the class to which the instance belongs.

  • Each instance has a pointer to a Class object to indicate its type, and these Class objects constitute the Class inheritance system.
  • If the object type cannot be determined during compilation, you should use the type information query method
  • Try to use the type information query method to determine the object type, instead of comparing the class object directly, because some objects may implement the message forwarding function.
15. Use a prefix to avoid namespace conflicts

You should add a proper prefix to all names. For example, if your company is focusing on semantic Widgets, you can use EWS as the prefix in some common code, if some code is only used in Browser projects of valid Browser, you can use EWB as the prefix.

The prefix should be three letters, because Apple claims that it retains all "two-letter Prefixes ".

  • Select the name associated with your company, application, or both as the prefix of the class name, and use this prefix in all codes.
  • If a third-party library is used in the self-developed library, the name should be prefixed.
16. provides the "all-around initialization method"

UITableViewCell: Specifies the style and identifier when initializing this type of object. The identifier can distinguish different types of cells. Because the creation cost of this object is high, therefore, you can reuse a table based on the identifier to improve program efficiency. The initialization method that provides the necessary information for the object so that it can complete the work is called "all-around initialization method ".

// For example, create an NSDate-(id) init;-(id) initWithString :( NSString *) string;-(id) initWithTimeIntervalSinceNow :( NSTimeInterval) seconds;-(id) initWIthTimeIntervalSinceRefrenceDate :( NSTimeInterval) seconds;

The fourth method is the all-around initialization method. That is to say, all other initialization methods must call it. When the underlying data storage mechanism changes, you only need to modify the code of this method.

  • Provides an all-around Initialization Method in the class and specifies it in the document. Other initialization methods should call this method
  • If the omnipotent initialization method is different from the superclass, the corresponding method in the superclass needs to be rewritten.
  • If the superclass initialization method does not apply to subclasses, you should repeat this superclass method and throw an exception in it.
17. Implement the description method

When debugging a program, you often need to print and view the object information. We can rewrite the description method of the object as follows:

  • The description method returns a meaningful string to describe the instance.
  • If you want to print more detailed object description information during debugging, you should implement the debugDescription method.
18. Try to use immutable objects

When designing a category, we should make full use of attributes to encapsulate data, and try to set the published attributes as read-only, and only publish the attributes when necessary.

  • Try to create immutable objects
  • If an attribute can only be modified inside the object, it is changed from readonly to readwrite in the. m file.
  • Instead of making the variable collection public as an attribute, you should provide relevant methods to modify the collection in the object.
19. Use clear and coordinated naming methods

Notes for naming a method:

  • If the return value of a method is newly created, a word in the method name should be of the type of the return value unless there are also modifiers such as localizedString. The attribute access method does not follow this naming method.
  • Place the nouns that indicate the parameter type before the parameter.
  • If the method is to perform operations on the current object, it should contain verbs.
  • Do not use str for short.
  • The "is" prefix must be added to the "Boolean" attribute. If a method returns a non-attribute Boolean value, use has or is as the prefix based on its function.
  • Leave the get prefix to the methods that use the "output parameter" to save the returned value.

Summary:

  • The standard OC naming rules should be followed, so that the interfaces created are easier for developers to understand.
  • Method name should be concise
  • Do not use the scaled type name for the method name
  • The top priority when naming a method is to ensure that its style is consistent with your own code or the framework to be inherited.
20. Add a prefix to the private method name

A class usually does more things than you can see from the outside. When writing class implementation code, you often need to write some internal methods. Some prefixes should be added to the name of this method, which helps debugging, because it is easy to differentiate Public and Private methods.

The specific prefix can be determined based on your preferences. It is best to include underlines and letters p, such as p_method. Do not use _ method, because Apple prefers to use a single underline as the prefix of the private method, which may cause a conflict.

  • Add a prefix to the name of the private method, so that it can be easily separated from the public method.
  • Do not use an underscore as the prefix of a private method, because this method is reserved for Apple.
21. Understand the OC Error Model
  • An exception is used only when a serious error occurs that can cause the entire application to crash.
  • If the error is not serious, use NSError
22. Understand the NSCopying Protocol
  • If you want to copy the object you write, you need to implement the NSCopying protocol.
  • If the custom objects are variable and immutable, The NSCopying and NSMutableCopying protocols must be implemented simultaneously.
  • When copying an object, you must decide whether to use the shortest copy or shortest COPY method. Generally, the shortest COPY method is used.
23. Communication between objects through delegation and Data Source protocols

Delegation mode: defines a set of interfaces. If an object wants to accept another object's delegation, You need to implement this interface to become its "delegate object ", the "other object" can return some information to the delegate object, or notify the delegate object in the event of a related event.

  • The delegate mode provides an interface for objects so that they can notify other objects of related events.
  • Define the interfaces that the delegate object should support as protocols, and define the events that may need to be processed as methods in the Protocol.
  • When an object needs to obtain data from another object, you can use the delegate mode, such as the dataSource of tableView.
  • If necessary, you can implement struct containing bits and cache the information about whether the delegate object can respond to related Protocol methods. For example, you can declare an attribute and record whether a method is implemented.
24. Spread the implementation code of classes to several categories that are easy to manage
  • Use the classification mechanism to divide the class implementation code into small pieces that are easy to manage
  • The "Private" method should be considered to be classified into Private categories to hide implementation details.
25. Always prefix the category names of third-party classes

For example, if you want to add a method to the system class, if you do not add a prefix, the method may be overwritten.

  • When adding a category to a third-party class, you should always add a special prefix to its name.
  • Add a special prefix to the method name.
26. Do not declare attributes in classification.
  • Define all attributes used to encapsulate data in the main interface
  • In classification, you can define an access method, but do not define attributes.
27. Use "class-continuation Classification" to hide Implementation Details

"Class-continuation Classification" is different from normal classification. It must be defined in the tired implementation file in which it is attached. It is important that this is the only classification that can declare instance variables, and there is no specific implementation file for this classification. The methods should be defined in the main implementation file of the class. In addition, unlike other categories, it has no name, for example:

@interface Person ()// Methods here@end
  • Use "class-continuation Classification" to add instance variables to the class
  • If an attribute is declared as read-only in the main interface, and the class must be modified using the setting method, it is extended to "readable and writable" in "class-continuation classification"
  • Declare the prototype of the private method in "class-continuation classification ".
  • To make the protocols that the class complies with unknown, you can declare them in "class-continuation classification.
28. provide anonymous objects through protocols

The following code:

@property (nonatomic, weak) id <WCEDelegate> delegate;

Because the type id of this attribute <EOCDelegate>, in fact, any class object can act as this attribute. For classes with this attribute, delegate is "anonymous".

  • The Protocol provides the anonymous type to some extent. The specific object type can be reduced to the id type that complies with a certain protocol, which specifies the method that the object should implement.
  • Use an anonymous object to hide the type name
  • If a specific type is not important, but an object can respond to a specific method (defined in the Protocol), it can be represented by an anonymous object.
29. Understanding reference count
  • The reference counting mechanism manages the memory by progressively decreasing the counter. After an object is created, its retention count is at least 1. If the retention count is positive, the object continues to survive. When the retention count is 0, the object is destroyed.
  • During the object declaration period, the remaining objects are retained or released through reference. The retention and release operations increase and decrease the retention count respectively.
30. ARC considerations
  • After ARC, programmers don't have to worry about memory management.
  • Do not manually manage
  • CoreFoundation objects are not managed by ARC. Developers must call CFRetain/CFRelease in a timely manner.
31. In the dealloc method, only the reference is released and the listener is removed.

After an object Passes its lifecycle, it will be recycled by the system. In this case, the dealloc method is executed. Within the lifecycle of each object, this method is executed only once, that is, when the reserved count is 0, it cannot be guaranteed when it is executed.

In the dealloc method, observation behaviors are usually removed and notifications are deregistered.

  • In the dealloc method, you should release the reference pointing to other objects, and cancel notifications such as the subscribed "kvo" or notification center. Do not do other things.
  • If the object holds system resources such as file descriptors, you should write a method to release such resources.
  • The method used to execute an asynchronous task should not be in dealloc, but in the normal state, which methods should not be called in dealloc, because the object is already in the recycle state.
32. Avoid circular references with weak references

If two objects are referenced by each other, both objects cannot be released, resulting in Memory leakage.

Difference between unsafe_unretained and weak:

After a reference pointing to an instance is removed, the unsafe_unretained attribute still points to the recycled instance, and the weak attribute points to nil. Weak makes the code safer than the unsafe_unretained application.

  • When some references are set to weak, circular references can be avoided.
  • The weak reference can be cleared automatically or not.
33. automatically release the pool
  • The automatically released pool is arranged in the stack. After an object receives the autorelease message, the system puts it into the top pool.
  • Reasonable Use of the automatic release pool can reduce the memory peak of applications
  • Use @ autoreleasepool
34. Create typedef for common block types

For example:

typedef void(^WCECompletionHander)(NSData *data);
  • Using typedef to redefine the block type makes it easier to use block variables.
  • When defining a new type, follow the naming rules
35. Use block to reduce code Dispersion
  • When creating an object, you can use the inline handler code block to declare the relevant business logic.
  • For example, network requests generally use code blocks to call data back and forth.

 

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.