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 to
readonly
. - Set to in the implementation file
readwrite
.
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.h
Keep 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