Any fool can write code that a computer can understand. A good programmer is one who writes code that humans can easily understand. – anonymous

This article is a set of iOS development guidelines based on the company’s code specification requirements, the zen and the Art of Objective-C programming and Effective Objective-C 2.0 books I read, and related blogs. Have insufficient place, welcome the blog to leave a message.

Curly braces

Except for methods in.m files, the curly braces “{” do not need another line. Recommendation:

if(! error) {return success;
}

- (void)doHomework
{
    if (self.hungry) {
        return; } / /doSomething
}
Copy the code

The operator

1. No Spaces between unary operators and variables:

! aValue-aValue // Negative ~aValue // bit non-+ +iCount *strSourceCopy the code

2. Binary operators must have Spaces between variables

fWidth = 5 + 5;
fLength = fWidth * 2;
for(int i = 0; i < 10; i++)
Copy the code

When the second argument to the ternary operator (the if branch) returns the same object as the one already checked in the conditional statement, the following expression is more dexterous:

result = object ? : [self createObject];
Copy the code

Is not recommended:

result = object ? object : [self createObject];
Copy the code

If statement

1. Try to list all the situations and give clear results.

Recommendation:

var hintStr;
if (count < 3) {
  hintStr = "Good";
} else {
  hintStr = "";
}

Copy the code

When programming with conditional statements, the left margin of the code should be a “gold” or “happy” path.

Recommendation:

- (void)someMethod {
    if(! [someOther boolValue]) {return;
    }
    // Do something important
}
Copy the code

If conditional expressions are complex, they need to be extracted and assigned to a BOOL variable. Recommendation:

BOOL nameContainsSwift  = [sessionName containsString:@"Swift"];
BOOL isCurrentYear      = [sessionDateCompontents year] == 2019;
BOOL isSwiftSession     = nameContainsSwift && isCurrentYear;

if (isSwiftSession) {
    // Do something very cool
}
Copy the code

A Yoda expression is one that compares a constant to a variable rather than a variable to a constant. Recommendation:

if (count == 6) {
}
Copy the code
if (myValue == nil) {
}
Copy the code
if(! object ) { }Copy the code

Is not recommended:

if ( 6 == count) {
}
Copy the code
if ( nil == object ) {
}
Copy the code

5. Conditional bodies should always be surrounded by braces Although you can sometimes leave the braces out (for example, if the conditional body has only one line of text), doing so can be problematic. Recommendation:

if(! error) {return success;
}
Copy the code

Is not recommended:

if(! error)return success;
Copy the code
if(! error)return success; 
Copy the code

A Switch statement

1. Each branch must be enclosed in braces

Recommendation:

switch (integer) {  
  case1: {/ /...break;  
  }
  case2: {/ /...break;  
  }  
  case3: {/ /...break; 
  }
  default:{
    // ...  
    break; }}Copy the code

2. All but enumerated types must have default branches

switch (menuType) {  
  case menuTypeLeft: {
    // ...  
    break; 
   }
  case menuTypeRight: {
    // ...  
    break; 
  }
  case menuTypeTop: {
    // ...  
    break; 
  }
  case menuTypeBottom: {
    // ...  
    break; }}Copy the code

If the default branch is used when the Switch statement uses enumeration types, the compiler will not be able to check the new enumeration types in the future.


function

1. Limit the length of a function to 50 lines. If there are too many lines of code in a method, the code reading experience will be terrible.

2. A function does one thing (Single rule) The responsibilities of each function should be clearly delineated (just like classes).

3. For functions that return values, make sure that each branch has a return value

Recommendation:

int function()
{
    if(condition1){
        return count1
    }else if(condition2){
        return count2
    }else{
       return defaultCount
    } 
}
Copy the code

4. Check whether the parameter is non-null and the validity of its data type. If the parameter is incorrect, the system returns or asserts the parameter immediately

Recommendation:

void function(param1,param2)
{
      if(! param1){return;
      }
      if(! param2){return;
      }
     //Do some right thing
}
Copy the code

5. If multiple functions have the same logical code, you are advised to extract the duplicate parts and call them as independent functions

6. If method parameters are too many and too long, you are advised to write them in multiple lines, with each parameter occupying one line and using colons to align them.

- (void)initWithAge:(NSInteger)age
               name:(NSString *)name
             weight:(CGFloat)weight;
Copy the code

7. Do not use and in the method name, and the signature must be consistent with the corresponding parameter name

Recommendation:

- (instancetype)initWithWidth:(CGFloat)width height:(CGFloat)height;
Copy the code

Is not recommended:

- (instancetype)initWithWidth:(CGFloat)width andHeight:(CGFloat)height;
Copy the code

annotation

1. Class comments Comments for classes are written at the top of the current class file.

2. Attribute comment It is recommended to write the comments on the attribute above the attribute. When using the attribute, there will be a prompt function.

@property (nonatomic, strong) UIButton *refreshBtn;Copy the code

3. Method Annotations For method annotations in the. H file, use the command+option+/ shortcut key to quickly comment. For method comments in the.m file, add // at the top of the method, with a space between the comment and the comment content. For example,

// load network data
Copy the code

4. Functional annotation In version iteration, develop on the basis of code written by colleagues, be sure to write the functional annotation of the version, which is convenient to ask about specific functions. recommended

// This is a new feature added v5.20.0 by minJing.linCopy the code

variable

1. The variable name must use the hump format class, and the protocol uses the big hump:

HomePageViewController.h
<HeaderViewDelegate>
Copy the code

Local variables such as objects use small humps:

NSString *personName = @"";
NSUInteger totalCount = 0;
Copy the code

2. The name of a variable must contain both function and type

UIButton *addBtn 
UILabel *nameLbl 
NSString *addressStr
Copy the code

3. Add suffixes to common class instance variable declarations

type The suffix
UIViewController VC
UIView View
UILabel Lbl
UIButton Btn
UIImage Img
UIImageView ImagView
NSArray Arr
NSMutableArray Marr
NSDictionary Dict
NSMutableDictionary Mdict
NSString Str
NSMutableString Mstr
NSSet Set
NSMutableSet Mset

constant

1. Constants are prefixed with the name of the related class

Recommendation:

The static const NSTimeInterval ZOCSignInViewControllerFadeOutAnimationDuration = 0.4;Copy the code

Is not recommended:

Static const NSTimeInterval fadeOutTime = 0.4;Copy the code

2. Use type constants instead of #define preprocessing

Let’s start by comparing the two declared constants:

  • Preprocessing commands: simple text replacements that do not include type information and can be modified at will.
  • Type constants: Contain type information and can be scoped and cannot be modified.

Recommendation:

Static const CGFloat ZOCImageThumbnailHeight = 50.0f;Copy the code

Is not recommended:

#define CompanyName @"Apple Inc." 
#define magicNumber 42 
Copy the code

3. Make a constant public

If we need to send a notification, we need to get the notification’s “channel” string (the name of the notification) in a different place, which obviously cannot be easily changed and can be retrieved in a different place. At this point, you need to define a visible string constant.

Recommendation:

//.h
extern NSString *const ZOCCacheControllerDidClearCacheNotification;
Copy the code
//.m
static NSString * const ZOCCacheControllerDidClearCacheNotification = @"ZOCCacheControllerDidClearCacheNotification";
Copy the code

The macro

1. Use all capital letters between words_segmentation

#define URL_GAIN_QUOTE_LIST @"/v1/quote/list"
#define URL_UPDATE_QUOTE_LIST @"/v1/quote/update"
Copy the code

2. If the macro definition contains expressions or variables, the expressions and variables must be enclosed in parentheses

#define MY_MIN(A, B)  ((A)>(B)?(B):(A))
Copy the code

The enumeration

When using enUms, it is recommended to use the new fixed base type definition because of its more powerful type checking and code completion.

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

paradigm

It is recommended to use generics when defining NSArray and NSDictionary to ensure program security:

NSArray<NSString *> *testArr =@[@"hello"The @"world"];
NSDictionary<NSString *, NSNumber *> *dic = @{@"key": @ @ (1)"age": @ (10)};Copy the code

NSMutableArray

1. Make a non-null judgment before addObject.

2. Determine whether the subscript is out of bounds.

3. Use firtstObject and lastObject when fetching the first or last element


Literal grammar

Use literal values to create immutable objects such as NSString, NSDictionary, NSArray, and NSNumber:

Recommendation:

NSArray *names = @[@"Brian"The @"Matt"The @"Chris"The @"Alex"The @"Steve"];
NSDictionary *productManagers = @{@"iPhone" : @"Kate"The @"iPad" : @"Kamal"The @"Mobile Web" : @"Bill"}; 
NSNumber *shouldUseLiterals = @YES;
NSNumber *buildingZIPCode = @10018; 
Copy the code

Is not recommended:

NSArray *names = [NSArray arrayWithObjects:@"Brian"The @"Matt"The @"Chris"The @"Alex"The @"Steve", nil];
NSDictionary *productManagers = [NSDictionary dictionaryWithObjectsAndKeys: @"Kate"The @"iPhone"The @"Kamal"The @"iPad"The @"Bill"]; NSNumber *shouldUseLiterals = [NSNumber numberWithBool:YES]; NSNumber *buildingZIPCode = [NSNumber numberWithInteger:10018];Copy the code

Block

Creating typedef for common Block types If we need to repeatedly create a variable of a Block (same argument, return value), we can use a typedef to define a Block’s own new type.

Such as:

int (^variableName)(BOOL flag, int value) =^(BOOL flag, int value)
{
     // Implementation
     return someInt;
}
Copy the code

This Block takes a bool and an int and returns an int. We can define a type for it:

typedef int(^EOCSomeBlock)(BOOL flag, int value);
Copy the code

When redefined, this can be done with a simple assignment:

EOCSomeBlock block = ^(BOOL flag, int value){
     // Implementation
};
Copy the code

Define blocks as arguments:

- (void)startWithCompletionHandler: (void(^)(NSData *data, NSError *error))completion;
Copy the code

The Block here has an NSData parameter, an NSError parameter that has no return value

typedef void(^EOCCompletionHandler)(NSData *data, NSError *error); - (void) startWithCompletionHandler (EOCCompletionHandler) completion;"Copy the code

The advantage of defining a Block signature through a typedef is that if you want to add parameters to a Block, you can only modify the line of code that defines the signature.


attribute

Write rules @property, Spaces, parentheses, thread modifiers, memory modifiers, read and write modifiers, Spaces, classes, object names; Choose appropriate modifiers for different scenarios.

Recommendation:

@property (nonatomic, copy, readonly) NSString *name;
@property (nonatomic, strong, readwrite) UIView *headerView;
@property (nonatomic, weak) id<#delegate#> delegate;
Copy the code

2. The Block attribute should use the copy keyword

Recommendation:

typedef void (^ErrorCodeBlock) (id errorCode,NSString *message);
@property (nonatomic, copy) ErrorCodeBlock errorBlock;

@property (nonatomic, copy) <#returnType#> (^<#Block#>)(<#parType#>);
Copy the code

3. Getters for BOOL attributes should be prefixed with is

Recommendation:

@property (nonatomic, assign, getter=isEditable) BOOL editable;
Copy the code

4. Try to use immutable objects externally

Try to make the properties published to the public read-only and inside the implementation file read/write. The specific approach is:

  • In the header file, set the object property toreadonly.
  • Set to in the implementation filereadwrite.

This way, the data can only be read externally, not modified, making the data held by instances of the class more secure. Also, for objects of the collection class, you should carefully consider whether you can make them mutable.

If you can only set it as a read-only property in the public part, store a variable in the private part. So when we get this property externally, we only get an immutable version of the internal variant, for example:

In the public API:

@interface EOCPerson : NSObject

@property (nonatomic, copy, readonly) NSString *firstName;
@property (nonatomic, copy, readonly) NSString *lastName;
@property (nonatomic, strong, readonly) NSSet *friends // public immutable set - (id)initWithFirstName:(NSString*)firstName andLastName:(NSString*)lastName; - (void)addFriend:(EOCPerson*)person; - (void)removeFriend:(EOCPerson*)person; @endCopy the code

Here, we set the Friends property to an immutable set. Public interfaces are then provided to add and remove elements from the set.

In the implementation file:

@interface EOCPerson () @property (nonatomic, copy, readwrite) NSString *firstName; @property (nonatomic, copy, readwrite) NSString *lastName; @end @implementation EOCPerson { NSMutableSet *_internalFriends; } - (NSSet*)friends {return[_internalFriends copy]; // The get method always returns a variableset} - (void)addFriend (EOCPerson*)person {[_internalFriends addObject:person]; // Add a collection element externallydosomething when add element } - (void)removeFriend:(EOCPerson*)person { [_internalFriends removeObject:person]; // Remove an element externally //do something when remove element
}

- (id)initWithFirstName:(NSString*)firstName andLastName:(NSString*)lastName 
{

     if ((self = [super init])) {
        _firstName = firstName;
        _lastName = lastName;
        _internalFriends = [NSMutableSet new];
    }
 return self;
}

Copy the code

We can see that in the implementation file, a mutable set is kept to record external additions and deletions.

The most important code here is:

- (NSSet*)friends 
{
   return [_internalFriends copy];
}

Copy the code

This is how to get the Friends property: it copies the currently saved mutable set to an immutable set and returns it. Therefore, externally read sets will be immutable versions.


Proxy method

1. The first argument to the proxy method must be the proxy

Proxy methods must take the delegate as the first argument (see UITableViewDelegate). The purpose is to distinguish between instances of different delegates. Because the same controller can be a proxy for multiple TableViews. Such as:

-  (void)tableView:(UITableView *)tableView 
didSelectRowAtIndexPath:(NSIndexPath *)indexPath
Copy the code

2. Determine whether the agent implements this method when sending messages to the agent

Recommendation:

if ([self.delegate respondsToSelector:@selector(signUpViewControllerDidPressSignUpButton:)]) { 
 [self.delegate signUpViewControllerDidPressSignUpButton:self]; 
} 
Copy the code

3. Follow too many agents when the newline alignment display is recommended:

@interface ShopViewController () <UIGestureRecognizerDelegate,
                                  HXSClickEventDelegate,
                                  UITableViewDelegate,
                                  UITableViewDataSource>

Copy the code

4. The proxy approach needs to be clear about what is required and what is not

  • @required: Methods that must be implemented
  • @optional: Optional implementation method
@protocol ZOCServiceDelegate <NSObject>
@optional
- (void)generalService:(ZOCGeneralService *)service didRetrieveEntries:(NSArray *)entries; 
@end 

Copy the code

class

1. Class names should be prefixed with three uppercase letters; When creating a subclass, place the section that represents the characteristics of the subclass between the prefix and the name of the parent class.

Recommendation:

/ / parent ZOCSalesListViewController / / subclass ZOCDaySalesListViewController ZOCMonthSalesListViewControllerCopy the code

2. All methods that return class objects and instance objects should use InstanceType

Using the instanceType keyword as a return value allows the compiler to do type checking, as well as subclass checking. This ensures that the return type is correct (it must be the current class object or instance object).

Recommendation:

- (instancetype)init 
{ 
    self = [super init]; // call the designated initializer 
    if (self) { 
        // Custom initialization 
    } 
    return self; 
} 

Copy the code
@interface ZOCPerson
+ (instancetype)personWithName:(NSString *)name; 
@end 

Copy the code

Is not recommended:

@interface ZOCPerson
+ (id)personWithName:(NSString *)name; 
@end 

Copy the code

3. In the class.hKeep references to other header files to a minimum

Sometimes class A needs instance variables of class B as attributes of its public API. At this point, we should not introduce headers of class B, but rather use the class keyword forward declaration and reference B’s header in A’s implementation.

// 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; // EOCEmployer as attribute @end // eocperson.m#import "EOCEmployer.h"

Copy the code

Advantages:

  • If you don’t include B’s header in A’s header file, you don’t include all of B’s content at the same time, which reduces compilation time.

  • Circular references can be avoided: if two classes import each other’s header files in their own header files, one of them will not compile properly.

Occasionally, however, we must introduce headers from other classes:

  • If the class inherits from a class, the parent class’s header file should be imported.
  • If the class complies with a protocol, the header file for that protocol should be imported. And it’s best to keep the protocol in a separate header file.

4. Class layout

#pragma mark - Life Cycle Methods
- (instancetype)init
- (void)dealloc

- (void)viewWillAppear:(BOOL)animated
- (void)viewDidAppear:(BOOL)animated
- (void)viewWillDisappear:(BOOL)animated
- (void)viewDidDisappear:(BOOL)animated

#pragma mark - Override Methods

#pragma mark - Network Methods

#pragma mark - Target Methods

#pragma mark - Public Methods

#pragma mark - Private Methods

#pragma mark - UITableViewDataSource  
#pragma mark - UITableViewDelegate  

#pragma mark - Setters and Getters

Copy the code

You can use one-click generation of code blocks to quickly develop code blocks by referring to Xcode


The judgment of equality

A reasonable way to determine if two Person classes are equal:

-  (BOOL)isEqual:(id)object 
{

    if (self == object) {  
        returnYES; // Check memory address}if(! [object isKindOfClass:[ZOCPerson class]]) {returnNO; // Is the current class or derived class}return[self isEqualToPerson:(ZOCPerson *)object]; } // define the equality method - (BOOL)isEqualToPerson:(Person *) Person {if(! person) {returnNO; } BOOL namesMatch = (! self.name && ! person.name) || [self.name isEqualToString:person.name]; BOOL birthdaysMatch = (! self.birthday && ! person.birthday) || [self.birthday isEqualToDate:person.birthday];return haveEqualNames && haveEqualBirthdays; 
} 

Copy the code

Picture naming

FileType [function]project[pageName]imageName[status]{.png,@2x.png,@3x.png} Category _ Function _ Module _ Page _ Name _ Status.png

[email protected]
Copy the code

Interview questions (style correction)

typedef  enum{
    UserSex_Man,
    UserSex_Woman
}UserSex;
@interface UserModel :NSObject

@property(nonatomic, strong) NSString *name;
@property (assign,nonatomic) int age;
@property (nonatomic,assign) UserSex sex;

-(id)initUserModelWithUserName: (NSString*)name withAge(int age);

-(void)doLogIn;
@end

Copy the code

References:

Zen and the Art of Objective-C iOS code specification after looking at this your team’s code is very standard Effective Objective-C 2.0