The software life cycle runs through the process of product development, testing, production, user use, version upgrade and later maintenance. Only the software code that is easy to read and maintain has vitality.

A, thinking

Recently, I reconstructed the project components and found some problems in naming and method segmentation in the project. I sorted out the iOS engineering specifications based on my usual experience and Apple official code specifications. Put forward the first version, if there is any imperfections later, continue to put forward and improve, the document is recorded here for the purpose of better code readability, later people or others in the team to see the code can not cause a large cost of time because of the code style and readability.

First sort out the specifications, and then use some scripts to improve the convenience and efficiency of everyone to use, and finally develop some collaborative scripts.

Two, some principles

  1. Long, descriptive method and variable names are good. Don’t use abbreviations unless it’s something that everyone knows about, like VIP. Do not use bgView, backgroundView is recommended
  2. The name shows the meaning. Clear meaning, do a good job of uncommented code self-expression ability. (Provided the code is canonical enough)
  3. Don’t get too technical and make your code less readable
  4. Remove unnecessary code. Let’s say we create a new controller, and there’s some code in there that we don’t need, or some code that’s commented out, and if it’s not needed, we just delete it and let it go? Next time I need to write it by hand
  5. Do not double evaluate a value inside a method; you can cache the results if appropriate
  6. Minimize the use of singletons.
  7. Providing a unified data management portal, whether MVC, MVVM, MVP module provides a unified data management portal to make code easier to manage and maintain.
  8. Except for methods in.m files, “{” does not need a new line.
- (void)getGooodsList
{
    ...
}

- (void)doHomework
{
    if (self.hungry) {
        return;
    }
    if (self.thirsty) {
        return;
    }
    if (self.tired) {
        return;
    }
    papapa.then.over;
}
Copy the code

variable

  1. A variable should have only one use, and do not assume that a variable can be used for more than one purpose to save lines of code. (Single principle)
  2. If there are local variables inside a method, the local variables should be near where they are used, rather than declaring all local variables at the top.

The operator

  1. No Spaces are required between the 1 meta-operator and the variable. For example: + + n
  2. The 2-element operator must be separated from the variable by a space. For example, containerWidth = 0.3 * Screen_Width
  3. When there are multiple operators, parentheses are used to clarify the correct order, which is more readable. For example: 2 << (1 + 2 * 3-4)

Conditional expression

  1. Line breaks are needed when conditions are too long or too long to make the code look neat
//good if (condition1() && condition2() && condition3() && condition4()) { // Do something } //bad if (condition1() && Condition2 () &&condition3 () &&condition4 () {// Do something}Copy the code
  1. Use it well when there is a possible situation in a block of codereturnTo end the abnormal situation.
- (void)doHomework
{
    if (self.hungry) {
        return;
    }
    if (self.thirsty) {
        return;
    }
    if (self.tired) {
        return;
    }
    papapa.then.over;
}
Copy the code
  1. The implementation of each branch must be included with {}.
// bad
if (self.hungry) self.eat() 
// good
if (self.hungry) {
    self.eat()
}
Copy the code
  1. The condition should be the variable on the left and the condition on the right. if ( currentCursor == 2 ) { //… }
  2. Each branch following the switch statement needs to be enclosed in braces.
  3. The default branch following the switch statement must exist unless the enumeration is being switched.
switch (menuType) { case menuTypeLeft: { ... break; } case menuTypeRight: { ... break; } case menuTypeTop: { ... break; } case menuTypeBottom: { ... break; }}Copy the code

The name of the class

  1. Capital camel name. Capitalize each word. Such as the “application for recording controller” ApplyRecordsViewController
  2. The name of each type ends with that type.
    • ViewController:ViewControllerAt the end. Example: ApplyRecordsViewController
    • View: use theViewAt the end. Example: Boundary: boundaryView
    • Use NSArray:sAt the end. Such as commodity classification data sources. categories
    • Use UITableViewCell:CellAt the end. Such as MyProfileCell
    • Protocol:DelegateorDatasourceAt the end. Such as XQScanViewDelegate
    • Tool: indicates a Tool class
    • Delegate class: Delegate
    • Service: Service

Class notes

Sometimes we need to set up comments for the classes we create. We can add it below the class.

The enumeration

Enumerations are named similar to classes.

typedef NS_ENUM(NSInteger, UIControlContentVerticalAlignment) {
    UIControlContentVerticalAlignmentCenter  = 0,
    UIControlContentVerticalAlignmentTop     = 1,
    UIControlContentVerticalAlignmentBottom  = 2,
    UIControlContentVerticalAlignmentFill    = 3,
};
Copy the code

The macro

  1. All caps, between words_The connection.
  2. In order toKAt the beginning. Follow the capital camel name. “No parameters”
#define HOME_PAGE_DID_SCROLL @"com.xq.home.page.tableview.did.scroll"
#define KHomePageDidScroll @"com.xq.home.page.tableview.did.scroll"
Copy the code

attribute

The writing rules are basically an empty space after the @property, parentheses, thread modifiers, memory modifiers, read and write modifiers, and an empty space for class object names depending on the situation.

@property (nonatomic, strong) UITableView *tableView;
@property (nonatomic, assign, readonly) BOOL loading;   
@property (nonatomic, weak) id<#delegate#> delegate;
@property (nonatomic, copy) <#returnType#> (^<#Block#>)(<#parType#>);
Copy the code

The singleton

Singletons are suitable for scenarios that manage status or events globally. Once created, the pointer to the object is stored in the static section, and the memory space allocated by the singleton in heap memory is freed only when the program destroys it. Because of this, we can only use singletons if we need to access only one object globally, like UIApplication objects, or more frequently. The life cycle of our function module is definitely shorter than the life cycle of App. If there are multiple singleton objects, it is bound to cost the App a lot. In a bad case, the system will kill the App. If you feel you must use singletons, make sure you tearDown them in the right place.

The usage scenarios of singletons are summarized as follows:

  • Control the use of resources, through thread synchronization to control concurrent access to resources.
  • Control the generation of instances to achieve the purpose of saving resources.
  • Control the sharing of data and allow communication between unrelated processes or threads without establishing a direct correlation.
+ (instancetype)sharedInstance
{
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        //because has rewrited allocWithZone  use NULL avoid endless loop lol.
        _sharedInstance = [[super allocWithZone:NULL] init];
    });
    
    return _sharedInstance;
}

+ (id)allocWithZone:(struct _NSZone *)zone
{
    return [TestNSObject sharedInstance];
}

+ (instancetype)alloc
{
    return [TestNSObject sharedInstance];
}

- (id)copy
{
    return self;
}

- (id)mutableCopy
{
    return self;
}

- (id)copyWithZone:(struct _NSZone *)zone
{
    return self;
}

Copy the code

Private variables

It is recommended to start with an underscore (_) in the.m file. For example NSString * _somePrivateVariable

Proxy method

  1. An instance of a class must be one of the parameters of a method.
  2. For continuous states, you can add will, did
  3. Start with the name of the class
- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath;

- (void)tableView:(UITableView *)tableView didEndDisplayingCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath;
Copy the code

methods

  1. Methods are separated by a line
  2. A large number of methods should be grouped together as groups as possible, such as lifecycle functions, public methods, private methods, set&& getters, proxy methods…
  3. The parentheses at the end of the method need a new line. Follow Apple’s specifications
  4. For parentheses in other scenarios, parentheses do not need a separate line break. Like the parentheses after the if.
  5. If method parameters are too long, multiple lines are recommended. Align with a colon.
  6. Keep the code in a method under 50 lines. As a rule of thumb, if a method has too many lines of code, the code reads poorly (don’t ask why, anyone who has refactored a method with too many lines of code will feel the same way).
  7. A function does one thing, one principle. After all the classes and methods are designed, a system can be implemented like building blocks.
  8. For a function that returns a value and has a branching case. Make sure that each branch has a return value.
  9. If a function has more than one parameter, it needs to check that the parameter is not null and the data type is valid. If the parameter is incorrect, do some measures: return immediately, assert.
  10. If multiple functions have the same logical code, you are advised to extract the same part and call it as an independent function
- (instancetype)init
{
    self = [super init];
    if (self) {
        <#statements#>
    }
    return self;
}

- (void)doHomework:(NSString *)name
            period:(NSInteger)second
            score:(NSInteger)score;
Copy the code
  1. Prepositions and conjunctions are required if the method has multiple arguments. A lot of times when you don’t know how to choose a test when thinking about some of apple’s API methods named.
//good
- (instancetype)initWithAge:(NSInteger)age name:(NSString *)name;

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath;


//bad
- (instancetype)initWithAge:(NSInteger)age andName:(NSString *)name;

- (void)tableView:(UITableView *)tableView :(NSIndexPath *)indexPath;
Copy the code
  1. .mPrivate methods in files need to be declared at the top
  2. There is also a sequencing problem between method groups.
  • At the top of the file to implement the declaration of attributes, private method declaration (many people omit this step, the problem is not big, but many third-party libraries are written, it looks like it will be very convenient, I suggest writing).
  • In life cycle methods, such as viewDidLoad, which only do interface addition, not interface initialization, all view initialization is recommended to be done in the getter. It is recommended that getters and setters be placed at the bottom so that the main logic of the code can be clearly seen at the top.
  • All button and gestureRecognizer response events are stored in this area.

The file is basically

//___FILEHEADER___ #import "___FILEBASENAME___.h" /*ViewController*/ /*View&&Util*/ /*model*/ /*NetWork InterFace*/ /*Vender*/ @interface ___FILEBASENAMEASIDENTIFIER___ () @end @implementation ___FILEBASENAMEASIDENTIFIER___ #pragma mark  - life cycle - (void)viewWillAppear:(BOOL)animated { [super viewDidAppear:animated]; } - (void)viewDidAppear:(BOOL)animated { [super viewDidAppear:animated]; } - (void)viewDidLoad { [super viewDidLoad]; self.title = <#value#>; } - (void)viewWillDisappear:(BOOL)animated { [super viewDidAppear:animated]; } - (void)viewDidDisappear:(BOOL)animated { [super viewDidAppear:animated]; } #ifdef DEBUG - (void)dealloc { NSLog(@"%s",__func__); } #endif #pragma mark - public Method #pragma mark - private method #pragma mark - event response #pragma mark - UITableViewDelegate #pragma mark - UITableViewDataSource //... #pragma mark-getters and setters@endCopy the code

Image resources

  1. Naming of individual files File resources also need to be named in the following form: Function Module name _ Category _ Function _ Status @nx. PNG [email protected], [email protected] , [email protected], [email protected],
  2. The folder name of resources should also refer to App to establish the corresponding entity folder directory according to the function module, and finally add the corresponding resource files to the corresponding directory.

annotation

  1. Comments for the class are written at the top of the current class file
  2. Comments for attributes need to be written after the attributes. //**
  3. For comments on methods in.h files, press the shortcut keys uniformlycommand+option+/. Three shortcut keys. Description of methods, return values, and parameters as required
  4. For comments on methods in.m files, add them next to methods//.
  5. There is a space between the comment and the comment content. Example: // Fetch goods list

Version of the specification

Use three-digit A.B.C names, such as 1.0.2, as updated

The version number Right description to align title The sample
A.b.c Belongs to the major content update 1.0.2 – > 2.0.0
a.B.c Updates that are part of a small section 1.0.2 – > 1.1.1
a.b.C Belongs to patch Update 1.0.2 – > 1.0.3

To improve the

After we know the address of the code block provided by the system and the folder address of the file template of the new controller, model and view in the normal development process of Xcode, Can we customize our own team style controller templates, and can we create and maintain our team’s frequently used code blocks?

The answer is yes.

Xcode blocks of code stored address: ~ / Library/Developer/Xcode/UserData/CodeSnippets Xcode document template store address: /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/Library/Xcode/Templates/File Templates/

meaning

  1. Code for individual and team developers is more standardized. Property is written in the order of Spaces, thread modifiers, and memory modifiers
  2. Provide a large number of usable code blocks to improve development efficiency. For example, if you type UITableView_init in Xcode, you can automatically create a UITabelView object. You just need to set the parameters in the specified location
  3. Improve code specification and avoid bugs with a few blocks of code. For example, I’ve seen code with block attributes decorated with strong, causing memory leaks. Let’s say you type in XcodeProperty_delegateWill come out@property (nonatomic, weak) id<<#delegate#>> delegate;You inputProperty_blockWill come out@property (nonatomic, copy) <#returnType#> (^<#Block#>)(<#parType#>);

Third, code block transformation

We can include properties, controller lifecycle methods, singleton methods to construct an object, proxy methods, blocks, GCD, lazy loading of UITableView, UITableViewCell registration, implementation of UITableView proxy methods, UICollectionVIew Lazy loading, registration of UICollectionVIewCell, implementation of proxy methods for UICollectionView, and so on are organized as Codesnippets

thinking

  • Once codesnippets are packaged, how will the team use them other than the people who wrote the project? How do I know if I have this code block?

    Solution: Hold a code specification meeting within the team so that everyone knows about it. Then they work together to maintain the Codesnippets. Usage, see below

    Property: Starts with Property_ and is automatically completed by the Enter key. For example, if the property type is Strong, the following format is automatically completed using the Property_Strong return key

    @property (nonatomic, strong) <#Class#> *<#object#>;
    Copy the code

    Method: confirm with Method_ keyword enter key, automatic completion. For example, the return key Method_UIScrollViewDelegate completes automatically in the following format

    #pragma mark - UIScrollViewDelegate
    - (void)scrollViewDidScroll:(UIScrollView *)scrollView {
        
    }
    Copy the code

    All kinds of common Mark: Mark_ key word enter confirmation, automatic completion. For example, the return key for Method_MethodsGroup is automatically completed in the following format

    #pragma mark - life cycle
    #pragma mark - public Method
    #pragma mark - private method
    #pragma mark - event response
    #pragma mark - UITableViewDelegate
    #pragma mark - UITableViewDataSource
    #pragma mark - getters and setters
    Copy the code
  • How to unify the team after codesnippets are encapsulated? Come up with a solution where the codesnippets on the team can be shared to Git and the rest of the team can pull the synchronization from the cloud. In this way, everyone on the team can code with the latest Codesnippets.

    Write shell scripts. A few key steps:

    1. Authorize system folders
    2. Create a folder for code blocks in the script folder
    3. Copy the code block under the system folder to the folder created in Step 2
    4. Commit all the current files to the Git repository

4. Modification of document template

Let’s look at the characteristics of the system file template, which corresponds to creating a new file template in Xcode.

So let’s create a Custom folder and copy the Cocoa Touch Class.xctemplate from the system Source folder into the Custom folder. Rename it to the name we want, and I’ll use “Power” as an example

Enter the PowerViewController xctemplate/PowerViewControllerObjective – C

Modify the contents of ___FILEBASENAME___. H and ___FILEBASENAME___

Replace the.h file with UIViewController, otherwise when other developers create new file templates, instead of UIViewController, we will see our PowerViewController

Modify TemplateInfo plist

Think about:

  • How to use

    Negotiate a logo (” Power “). For example, I created six templates, singleton, Controller, Model, UIView, UITableViewCell, and UicollectionViewCell, all starting with Power.

  • How to share

    Use shell scripts as tools. Use a script to synchronize the code template in the Git cloud to the corresponding location of the local Xcode folder. Key steps:

    1. Git Clone the code to the script folder
    2. Go to the folder where the Codesnippets are stored and copy the content to the place where the codesnippets are stored on the system
    3. Go to the file Template folder and copy the contents to the file template folder in the system

Six, the use of

1. Developed in Xcode

  • The Property attribute. Press Property_ automatic association, select the cursor, and press Enter for automatic completion

  • Mark identification. Click Mark_ automatic association, will display a variety of commonly used Mark, cursor movement after selected hit enter automatic completion

  • Method Method. Click Method_ to automatically associate, and various commonly used methods will be displayed. After the cursor is moved and selected, press Enter to automatically complete

  • The GCD. Click GCD_ automatic association, will display a variety of commonly used GCD, cursor movement after selected hit enter automatic completion

  • Lazy loading of common UI controls. Press _init for automatic association to display lazy loading of common UI controls. After the cursor is moved and selected, press Enter for automatic completion

  • The Delegate. Press Delegate_ to automatically associate, and a variety of commonly used delegates are displayed. Press Enter to automatically complete a cursor move

  • Notification. NSNotification_ automatic association will display various commonly used CODE blocks of NSNotification, such as sending notification, adding observer, removing observer, implementation of observer method, etc. After cursor movement is selected, press Enter to automatically complete

  • Protocol. Type Protocol_ Automatically displays code blocks of common protocols. Move the cursor and press Enter to complete the Protocol automatically

  • Memory-decorated code blocks

  • Engineering commonly used TODO, FIXME, Mark. Click Mark_ automatic association, will display a variety of commonly used Mark code blocks, cursor movement after selected, hit enter to automatically complete

  • Memory-decorated code blocks. Memory_ automatic association, will display a variety of commonly used memory modification code blocks, cursor movement selected after the press enter automatic completion

  • Some common code blocks. Press Thread_ and other automatic association, select and press Enter to automatically complete.

2. Code Snippet synchronization

You may be the creator of a block of code, or you may be the user of a block of code

Chmod +x./ syncsnipets. sh // Set executable permission for scripts./ syncsnipets. sh // Synchronize git cloud code blocks and file templatesCopy the code

If you have a new code block created and you feel good about it and want to synchronize it to the remote Github repo, you can use the following command

/ uploadmysnipets. sh // Set executable permission for the script./ uploadmysnipets. sh // Synchronize local code blocks and file templates to the cloudCopy the code

PS

Constantly improving. Everyone who has good or good code blocks or file templates would like to participate in this project and contribute to the improvement of our development efficiency

About 58 code sections and 6 class file templates have been created (UIViewController with method groups, models, thread-safe singletons, UIView with layout methods, UITableViewCell, UICollectionViewCell)

Shell scripts basically have code comments for each function and key step, so anyone who wants to learn the shell can look at the code. Code portal