Code format
Use Spaces instead of tabs
Do not use tabs in projects, use Spaces for indentation. Set Tab and auto indent to 4 Spaces in Xcode > Preferences > Text Editing. (Google’s standard is to use two Spaces for indentation, but the Xcode default is recommended.)
The maximum length of each line
Similarly, set the maximum line length to 80 in Xcode > Preferences > Text Editing > Page Guide at Column: Too long a line of code will cause readability problems.
Function writing
A typical Objective-C function would look like this:
- (void)writeVideoFrameWithData:(NSData *)frameData timeStamp:(int)timeStamp {
...
}
Copy the code
There should be a space between – and (void), and the first curly brace {at the end of the function line should also have a space.
If a function has too many arguments or a long name, it should be displayed in line with:
- (id)initWithModel:(IPCModle)model
ConnectType:(IPCConnectType)connectType
Resolution:(IPCResolution)resolution
AuthName:(NSString *)authName
Password:(NSString *)password
MAC:(NSString *)mac
AzIp:(NSString *)az_ip
AzDns:(NSString *)az_dns
Token:(NSString *)token
Email:(NSString *)email
Delegate:(id<IPCConnectHandlerDelegate>)delegate;
Copy the code
In lines, if the first paragraph is too short, subsequent names can be indented by the length of a Tab (4 Spaces) :
- (void)short:(GTMFoo *)theFoo
longKeyword:(NSRect)theRect
evenLongerKeyword:(float)theInterval
error:(NSError **)theError {
...
}
Copy the code
Line feed for parentheses
The question of whether parentheses should be wrapped is a perennial debate among programmers, but we recommend:
Keep code with branches (if, else, switch, while, etc.) on the same line as the closing parentheses () of the previous branch and the opening parentheses ((, {) of your own branch.
If (user.ishappy) {//... } else { // ... } // if (something) {//... } else { // ... } // Recommend [UIView animateWithDuration:1.0 animations:^{//...} completion:^(BOOL finished) {//...}];Copy the code
A function call
The format of the function call is similar to that of writing, which can be written on one or more lines depending on the length of the function:
[myObject doFooWith:arg1 name:arg2 error:arg3]; [myObject doFooWith:arg1 name:arg2 error:arg3]; [myObj short:arg1 longKeyword:arg2 evenLongerKeyword:arg3 error:arg4];Copy the code
The following is incorrect:
[myObject doFooWith:arg1 name:arg2 error:arg3]; [myObject doFooWith:arg1 name:arg2 error:arg3]; [myObject doFooWith:arg1 name:arg2 error:arg3];Copy the code
@public and @private tokens
The @public and @private tags should be indented with a space:
@interface MyClass : NSObject {
@public
...
@private
...
}
@end
Copy the code
Protocols
IPCConnectHandler()
. This rule applies to all protocols, including function declarations, class declarations, instance variables, and so on:
@interface MyProtocoledClass : NSObject<NSWindowDelegate> {
@private
id<MyFancyDelegate> _delegate;
}
- (void)setDelegate:(id<MyFancyDelegate>)aDelegate;
@end
Copy the code
Closure (Blocks)
Depending on the length of the block, there are different writing rules:
- Shorter blocks can be written on a single line.
- The closing parenthesis of the block, if displayed in line
}
It should be aligned with the first non-null character on the line that calls the block. - The code inside the block is indented by four Spaces.
- If the block is too large, it should be used as a separate variable.
^
和(
Between,^
和{
There are no Spaces between, and the closing parenthesis of the argument list)
和{
There is a space between them.
// Short blocks are written on one line [operation setCompletionBlock:^{[self onOperationDone];}]; [operation setCompletionBlock:^{[self.delegate newDataAvailable];}]; // Block calls using THE C API follow the same writing rule dispatch_async(_fileIOQueue, ^{NSString *path = [self sessionFilePath]; if (path) { // ... }}); // Long block keywords can be indented on a new line, Pay attention to the right parenthesis block '} 'and call block, the first line of code is not empty character alignment [[SessionService sharedService] loadWindowWithCompletionBlock: ^ (SessionWindow *window) { if (window) { [self windowDidLoad:window]; } else { [self errorLoadingWindow]; } }]; / / longer block parameter list can also be indented in the new row after writing [[SessionService sharedService] loadWindowWithCompletionBlock: ^(SessionWindow *window) { if (window) { [self windowDidLoad:window]; } else { [self errorLoadingWindow]; } }]; // Large blocks should be defined separately as variables using void (^largeBlock)(void) = ^{//... }; [_operationQueue addOperationWithBlock:largeBlock]; // Use multiple blocks in one call, noting that they are not aligned with ':' like functions, [myObject doSomethingWith:arg1 firstBlock:^(Foo *a) {//...} secondBlock:^(Bar *b) {//...}];Copy the code
Syntactic sugar for data structures
Use more readable syntactic sugar to construct data structures such as NSArray and NSDictionary, and avoid lengthy alloc init methods.
If the construction code is written on a single line, a space is required at both ends of the parentheses to distinguish the element being constructed from the construction syntax:
NSArray *array = @[[foo description], @"Another String", [bar description]]; NSArray *array = @[foo description], @"Another String", [bar description]]; NSDictionary *dic = @{ NSForegroundColorAttributeName : [NSColor redColor] }; NSArray* array = @[[foo description], [bar description]]; NSDictionary* dic = @{NSForegroundColorAttributeName: [NSColor redColor]};Copy the code
If the constructor is not on a single line, the constructor element needs to be indented with two Spaces, and the closing parenthesis] or} is on a new line and aligned with the first non-null character on the line that called the syntax sugar:
NSArray *array = @[
@"This",
@"is",
@"an",
@"array"
];
NSDictionary *dictionary = @{
NSFontAttributeName : [NSFont fontWithName:@"Helvetica-Bold" size:12],
NSForegroundColorAttributeName : fontColor
};
Copy the code
When constructing a dictionary, place a space between the Key and Value and the colon:.
// Correct, colon ':' followed by a space NSDictionary *option1 = @{NSFontAttributeName: [NSFont fontWithName:@"Helvetica-Bold" size:12], NSForegroundColorAttributeName : fontColor }; // Align NSDictionary *option2 = @{NSFontAttributeName: [NSFont fontWithName:@"Arial" size:12], NSForegroundColorAttributeName : fontColor }; NSDictionary *wrong = @{AKey: @"b", BLongerKey: @"c",}; NSDictionary *alsoWrong= @{AKey: @"a", BLongerKey: @"b"}; NSDictionary *stillWrong = @{AKey: @"b", BLongerKey: @"c",};Copy the code
Naming conventions
The basic principle of
clear
Naming should be as clear and concise as possible, but in Objective-C clarity is more important than brevity. Thanks to Xcode’s powerful autocomplete feature, we don’t have to worry about long names.
InsertObject :atIndex: // clear insertObject:atIndex: // clear insertObject:atIndex: // clear The object type of remove is not specified. The function of this parameter is not specified.Copy the code
Don’t use short words, spell out the full word:
DestSel setBkgdColor: destinationSelection setBackgroundColor: destinationSelection setBackgroundColor: destinationSelection setBackgroundColor: destinationSelection setBackgroundColor: destinationSelection setBackgroundColor: destinationSelection setBackgroundColor: destinationSelection setBackgroundColorCopy the code
However, there are some word abbreviations that are so common in Objective-C coding that they become a norm, and these abbreviations can be used directly in code. Here are some of them:
alloc == Allocate max == Maximum alt == Alternate min == Minimum app == Application msg == Message calc == Calculate nib == Interface Builder archive dealloc == Deallocate pboard == Pasteboard func == Function rect == Rectangle horiz == Horizontal Rep == Representation (used in class name such as NSBitmapImageRep). info == Information temp == Temporary init == Initialize vert == Vertical int == IntegerCopy the code
Avoid ambiguity when naming methods or functions
Return sendPort or send a Port. SendPort // is ambiguous, return a name attribute value or display a name action? displayNameCopy the code
consistency
Keep the naming style consistent throughout the project, preferably with the Apple SDK code. Methods that perform similar functions in different classes should have the same name. For example, we always use count to return the number of sets. We cannot use count in class A and getNumber in class B.
language
Always use English named variables instead of Pinyin or even Chinese:
// correct, indicating medicalRecord // error, do not use pinyin name! zhengLiaoJiLuCopy the code
Use prefixes
Naming prefixes are useful if the code needs to be packaged into a Framework for use by other projects, or if the project is so large that it needs to be broken up into different modules.
- Prefixes are capitalized abbreviations, as in Cocoa
NS
The prefix represents the Founation framework class,IB
Represents the Interface Builder framework. - You can use prefixes when naming classes, protocols, functions, constants, and typedef macros, but be careful not to use prefixes for member variables or methods, because they are inherently contained in the class namespace.
- Do not name prefixes that conflict with the Apple SDK framework.
/ / using XR (almond initials) prefix, said the App business module components @ interface XRPhotoAssetsViewController: KCFViewController / /... @endCopy the code
Named Classes and Protocols
The class name starts with an uppercase letter and should contain a noun to indicate the type of object it represents, with the necessary prefixes such as NSString, NSDate, NSScanner, NSApplication, etc:
// Use a noun (player) to name the class @interface XRVideoPlayer: NSObject... @endCopy the code
The protocol name should clearly indicate the behavior it performs and should be distinguished from the class name, so it is common to name a protocol using the ing end, such as NSCopying, NSLocking:
@protocol XRVersionUpdateProtocol <NSObject>... @protocol XRVersionUpdateProtocol <NSObject>... @endCopy the code
Some protocols contain a lot of unrelated functionality that serves a particular class, so you can simply name the protocol by the class name, such as the NSObject protocol, which contains a set of methods for the lifetime of the ID object.
Name Headers
The header name of the source should clearly indicate what it does and what it contains:
- If only a single class or protocol is defined in the header file, name the header file with the class name or protocol name, for example
NSLocale.h
Defines theNSLocale
Class. - If a header file defines a list of classes, protocols, or categories, name the header file using the dominant class name, for example
NSString.h
Defines theNSString
andNSMutableString
. - Each Framework should have a header file with the same name as the Framework, containing references to all common class headers in the Framework, such as
Foundation.h
- The Framework sometimes implements category extensions for classes in other frameworks, and such files are commonly used
The name of the extended framework
+Additions
In a way, for exampleNSBundleAdditions.h
.
Naming Methods
Objective-c method names are usually long to make programs more readable, according to Apple * “Good method names should be read aloud as a sentence” *.
Methods generally start with a lowercase letter, each subsequent word begins with a capital letter, and method names should not have punctuation marks (including underscores), with two exceptions:
- You can start with some generic capital abbreviations, for example
PDF
.TIFF
And so on. - You can name private methods or methods in a category with an underlined prefix.
If the method tells the object to perform an action, name it with a verb. Be careful not to use redundant keywords like do and does. The verb itself is suggestive enough:
// the verb begins with an action - (void)invokeWithTarget:(id)target; - (void)selectTabViewItem:(NSTabViewItem *)tabViewItem;Copy the code
If the method is to get the value of a property of an object, name the method with the property name. Be careful not to add get or other verb prefixes:
// Correct, use the attribute name to name the method - (NSSize)cellSize; // error, add extra verb prefix - (NSSize)calcCellSize; - (NSSize)getCellSize;Copy the code
For methods with multiple parameters, add a keyword before each parameter. The keyword should clearly state the function of the parameter:
- (void)sendAction:(SEL)aSelector toObject:(id)anObject forAllCells:(BOOL)flag; - (void)sendAction:(SEL)aSelector :(id)anObject :(BOOL)flag; // correct - (id)viewWithTag:(NSInteger)aTag; - (id)taggedView:(int)aTag;Copy the code
Do not concatenate two parameters with AN and, which is usually used to indicate that the method performs two relatively independent operations (by design, this should be split into two separate methods) :
/ / error, Do not use "and" to concatenate arguments - (int)runModalForDirectory:(NSString *)path andFile:(NSString *)name andTypes:(NSArray *)fileTypes; / / right, - (BOOL)openFile:(NSString *)fullPath withApplication:(NSString *)appName andDeactivate:(BOOL)flag;Copy the code
Method parameter names also have a few caveats:
- Like the method name, the first letter of the argument is lowercase and each word after it is capitalized
- Do not use similar methods in method names
pointer
.ptr
Such terms are used to indicate Pointers, and the type of the argument itself is sufficient - Do not use parameter names with only one or two letters
- Don’t use abbreviations. Spell out full words
Here are some common parameter names:
. action:(SEL)aSelector ... alignment:(int)mode ... atIndex:(int)index ... content:(NSRect)aRect ... doubleValue:(double)aDouble ... floatValue:(float)aFloat ... font:(NSFont *)fontObj ... frame:(NSRect)frameRect ... intValue:(int)anInt ... keyEquivalent:(NSString *)charCode ... length:(int)numBytes ... point:(NSPoint)aPoint ... stringValue:(NSString *)aString ... tag:(int)anInt ... target:(id)anObject ... title:(NSString *)aStringCopy the code
Accessor Methods
Access method refers to the method used to obtain and set the value of a class attribute. Different types of attributes correspond to different access method specifications:
// The access method paradigm when attribute is a noun - (type)noun; - (void)setNoun:(type)aNoun; NSString - (NSString *)title; - (void)setTitle:(NSString *)aTitle; // Attribute is an adjective access method normal form - (BOOL)isAdjective; - (void)setAdjective:(BOOL)flag; // Chestnut - (BOOL)isEditable; - (void)setEditable:(BOOL)flag; // Attribute is a normal form of a verb access method - (BOOL)verbObject; - (void)setVerbObject:(BOOL)flag; BOOL showsAlpha; - (void)setShowsAlpha:(BOOL)flag;Copy the code
Do not convert a verb to a passive form when naming an access method:
// correct - (void)setAcceptsGlyphInfo:(BOOL)flag; - (BOOL)acceptsGlyphInfo; // error, do not use passive form of verb - (void)setGlyphInfoAccepted:(BOOL)flag; - (BOOL)glyphInfoAccepted;Copy the code
Use can, should, and will to help express access methods, but do not use do, and does:
// correct - (void)setCanHide:(BOOL)flag; - (BOOL)canHide; - (void)setShouldCloseDocument:(BOOL)flag; - (BOOL)shouldCloseDocument; // error, do not use "do" or "does" - (void) setacceptglyphinfo :(BOOL)flag; - (BOOL)doesAcceptGlyphInfo;Copy the code
Why don’t you use the get prefix in Objective-C to denote property fetching methods? Because get in Objective-C is usually used only to represent a function that returns a value from a function pointer:
- (void)getLineDash:(float *)pattern count:(int *)count phase:(float *)phase;Copy the code
Naming a Delegate
When a particular event occurs, the object fires the delegate method it registers. Delegates are a common way of passing messages in Objective-C. Delegates have a fixed naming pattern.
The first argument to a delegate method is the object that triggered it, and the first keyword is the name of the class that triggered it, unless the delegate method has only one argument called sender:
- (BOOL)tableView:(NSTableView *)tableView shouldSelectRow:(int)row; - (BOOL)application:(NSApplication *)sender openFile:(NSString *)filename; / / when only a "sender" parameter can be omitted the name of the class - (BOOL) applicationOpenUntitledFile (NSApplication *) sender;Copy the code
Keywords such as should, will, and DID are used depending on the timing and purpose of the delegate method firing
- (void)browserDidScroll:(NSBrowser *)sender; - (NSUndoManager *)windowWillReturnUndoManager:(NSWindow *)window; , - (BOOL) windowShouldClose (id) sender;Copy the code
Collection Methods
Some objects manage a collection of other objects or elements, and need to use methods like “add, delete, modify” to operate on the collection. The naming paradigm of these methods is generally as follows:
- (void)addElement:(elementType)anObj; - (void)removeElement:(elementType)anObj; - (NSArray *)elements; - (void)addLayoutManager:(NSLayoutManager *)obj; - (void)removeLayoutManager:(NSLayoutManager *)obj; - (NSArray *)layoutManagers;Copy the code
Note that if the returned collection is unordered, use NSSet instead of NSArray. If you need to insert an element into a specific location, use a name like this:
- (void)insertLayoutManager:(NSLayoutManager *)obj atIndex:(int)index;
- (void)removeLayoutManagerAtIndex:(int)index;
Copy the code
If a managed collection element has Pointers to managed objects, set this type to weak to prevent reference loops.
Here’s how the NSWindow class works in the SDK:
- (void)addChildWindow:(NSWindow *)childWin ordered:(NSWindowOrderingMode)place;
- (void)removeChildWindow:(NSWindow *)childWin;
- (NSArray *)childWindows;
- (NSWindow *)parentWindow;
- (void)setParentWindow:(NSWindow *)window;
Copy the code
Named Functions
Functions are still needed in many cases, such as if an object is a singleton, then functions should be used instead of class methods.
There are some differences in the names and methods of functions, mainly:
- Function names are usually prefixed with abbreviations that denote the framework in which the method resides.
- The words following the prefix are shown in a “hump” notation, with the first word capitalized.
The first word of a function name is usually a verb that indicates what the method does:
NSHighlightRect
NSDeallocateObject
Copy the code
If a function returns an attribute of its argument, omit the verb:
unsigned int NSEventMaskFromType(NSEventType type)
float NSHeight(NSRect aRect)
Copy the code
If a function returns a value via a pointer argument, use Get in the function name:
const char *NSGetSizeAndAlignment(const char *typePtr, unsigned int *sizep, unsigned int *alignp)
Copy the code
The function is named when its return type is BOOL:
BOOL NSDecimalIsNotANumber(const NSDecimal *decimal)
Copy the code
Named properties and instance Variables (Properties&Instance Variables)
Attributes are associated with the access method of the object. The first letter of the attribute is lowercase, and the first letter of the subsequent word is uppercase. Attributes are named nouns or verbs by function:
// @property (strong) NSString *title; // @property (assign) BOOL showsAlpha;Copy the code
Attributes can also be named adjectives, in which case a get method prefixed with is is usually specified to improve readability:
@property (assign, getter=isEditable) BOOL editable;
Copy the code
To name instance variables, prefix the variable name with _ (some historical code will put _ after it), otherwise as if it were a named attribute:
@implementation MyClass {
BOOL _showsTitle;
}
Copy the code
In general, classes need to hide data store details from consumers, so instead of defining instance methods as publicly accessible interfaces, use the @private, @protected prefixes.
Not recommended, according to Appleinit
和 dealloc
Method to access instance variables directly, but many people believe that direct access makes the code more legible and that access method access is only used when you need to evaluate or perform operations, so this is not required.
Named Constants
If you want to define a set of related constants, use enumerations, which use the same naming conventions as functions. It is recommended to use the NS_ENUM and NS_OPTIONS macros to define the enum types, see the official Adopting Modern Objective-C article:
// define a typedef NS_ENUM(NSInteger, NSMatrixMode) {NSRadioModeMatrix, NSHighlightModeMatrix, NSListModeMatrix, NSTrackModeMatrix };Copy the code
Define a bit map:
typedef NS_OPTIONS(NSUInteger, NSWindowMask) {
NSBorderlessWindowMask = 0,
NSTitledWindowMask = 1 << 0,
NSClosableWindowMask = 1 << 1,
NSMiniaturizableWindowMask = 1 << 2,
NSResizableWindowMask = 1 << 3
};
Copy the code
Use const to define floating-point or single integer constants. Enumerations are preferred if you want to define a group of related integer constants. Constants have the same naming conventions as functions:
const float NSLightGray;
Copy the code
Do not use the #define macro to define constants. For integer constants, use enumerations. For floating-point constants, use const definitions. #define is usually used to tell the compiler whether to compile a block of code, as in the usual:
#ifdef DEBUG
Copy the code
Note that generally compilers define macros with a __ before and after, such as *__MACH__*.
Named Notifications
Notifications are often used to pass messages between modules, so notifications should represent events as closely as possible. The naming paradigm for notifications is:
[the class name of the trigger notifications] + [Did | Will] + [action] + NotificationCopy the code
Chestnut:
NSApplicationDidBecomeActiveNotification
NSWindowDidMiniaturizeNotification
NSTextViewDidChangeSelectionNotification
NSColorPanelColorDidChangeNotification
Copy the code
annotation
You and I know the pain of reading uncommented code. Good comments not only make your program easier to read, they also improve the quality of the code itself. Note that comments are meant to be understood by others, not just yourself.
File comment
File comments must be written to each file, and file comments usually contain
- Module where the file resides
- The author information
- Historical Version Information
- Copyright information
- The contents and functions of the file
A paragraph of well-documented chestnut:
/******************************************************************************* Copyright (C), 2011-2013, Andrew Min Chang File name: AMCCommonLib.h Author: Andrew Chang (Zhang Min) E-mail: [email protected] Description: This file provide some covenient tool in calling library tools. One can easily include library headers he wants by declaring the corresponding macros. I hope this file is not only a header, but also a useful Linux library note. History: 2012-??-??: On about come date around middle of Year 2012, file created as "commonLib.h" 2012-08- Copyright information: 20: Add shared memory library; add message queue. 2012-08-21: Add socket library (local) 2012-08-22: Add math library 2012-08-23: Add socket library (internet) 2012-08-24: Add daemon function 2012-10-10: Change file name as "AMCCommonLib.h" 2012-12-04: Add UDP support in AMC socket library 2013-01-07: Add basic data type such as "sint8_t" 2013-01-18: Add CFG_LIB_STR_NUM. 2013-01-22: Add CFG_LIB_TIMER. 2013-01-22: Remove CFG_LIB_DATA_TYPE because there is already AMCDataTypes.h This file was intended to be under GPL protocol. However, I may use this library in my work as I am an employee. And my company may require me to keep it secret. Therefore, this file is neither open source nor under GPL control. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * /Copy the code
The format of the file comments is usually not required, but it should be clear and legible, but the style should be uniform throughout the project.
Code comments
Good code is self-documenting, so comments on code blocks should be more documenting why they are done than what they are.
If it is confusing, we can properly state the meaning of the parameters, return values, functions, and possible side effects.
Comments should be updated and removed along with the code to ensure that they correspond.
There is no language requirement for annotations, either in Chinese or English, as long as they are clear and concise, avoid long paragraphs of lengthy annotations and unnecessary annotations.
The definition of methods, functions, classes, protocols and categories all need annotations. It is recommended to use Apple’s standard annotation style. The advantage is that you can automatically pop up annotations by Alt + clicking on the reference place, which is very convenient.
Xcode comes with comment shortcuts: option + command + /.
Some good notes:
/**
* Create a new preconnector to replace the old one with given mac address.
* NOTICE: We DO NOT stop the old preconnector, so handle it by yourself.
*/
- (void)refreshConnectorWithConnectType:(IPCConnectType)type Mac:(NSString *)macAddress;
/**
* Get the COPY of cloud device with a given mac address.
*
* @param macAddress Mac address of the device.
*
* @return Instance of IPCCloudDevice.
*/
- (IPCCloudDevice *)getCloudDeviceWithMac:(NSString *)macAddress;
// A delegate for NSApplication to handle notifications about app
// launch and shutdown. Owned by the main app controller.
@interface MyAppDelegate : NSObject {
...
}
@end
Copy the code
Comments on protocols and delegates should clearly state the conditions under which they are triggered:
/** Sent when failed to init connection, like p2p failed. */
-(void)initConnectionDidFailed:(IPCConnectHandler *)handler;
Copy the code
Coding style
Here are some of the Cocoa programming styles and notes we recommend.
use#pragma mark
Block code
In method-rich source files, use the #pragma mark tag to block code for different functions:
/ / use a # pragma mark region of the source code structure @ implementation XRVideoPlayerViewController # pragma mark - Public + (instancetype)playerWithUrl:(NSURL *)url {} + (void)play:(NSURL *)url {} #pragma mark - LifeCycle - (void)viewDidLoad {} - (void)dealloc {} #pragma mark - Configs - (void)preparePlayer {} - (void)initPlayerView {} #pragma mark - Actions - (void)longPress:(UILongPressGestureRecognizer *)gesture {} #pragma mark - XRVideoPlayerControlDelegate - (void)controlDidPaused {} - (void)controlDidStarted {} - (void)controlDidClose {} #pragma mark - Properties - (UIView *)playerView {} - (void)setUrl:(NSURL *)url {} #pragma mark - Utilities - (void)showNoWifiToast {} - (void)saveToAlbum {} #pragma mark - Overide - (BOOL)prefersStatusBarHidden {} @endCopy the code
Do not use the new method
Although you can often use new instead of the alloc init method, this can cause unexpected problems when debugging memory. The Cocoa specification uses the alloc init method, and using new can be confusing for some readers.
Keep your Public API as simple as possible
Common interfaces should be designed simply to meet the core functional requirements. Don’t design an API that is rarely used but has extremely complex parameters. If you want to define complex methods, use categories or class extensions.
# include and # import
#import is a common way of referring to header files in Cocoa. It automatically prevents multiple references to files. When do you use #import and when do you use #include?
- Used when referencing an Objective-C or Objective-C++ header file
#import
- Used when referencing a C or C++ header file
#include
, you must ensure that the referenced file provides the #define Guard.
Chestnut:
#import <Cocoa/Cocoa.h>
#include <CoreFoundation/CoreFoundation.h>
#import "GTMFoo.h"
#include "base/basictypes.h"
Copy the code
Why not use #import all together? The main purpose is to ensure that code is shared between platforms without problems.
References the root header file of the framework
Mentioned above, each frame will have a framework and the header file with the same name, it contains all the references within the framework of the interface, when using a framework should direct reference to the header file, rather than other sub-modules of header files, even if you only small part, the compiler will automatically complete optimization.
#import <Foundation/ foundation.h > #import <Foundation/ nsarray.h > #import <Foundation/ nsString.h >Copy the code
The use of the BOOL
BOOL is defined in Objective-C as signed char, which means that a BOOL variable can represent more than just YES(1) and NO(0), so never compare a BOOL variable to YES directly:
/ / error, can not be sure | great | value is YES (1), don't compare Boolean value directly with YES BOOL great = [foo isGreat]; if (great == YES) // ... be great! // correct BOOL great = [foo isGreat]; if (great) // ... be great!Copy the code
Similarly, do not return any other type of value as BOOL, in which case the BOOL variable is assigned only to the last byte of the value, which is likely to reach 0 (NO). However, some logical operators such as &&, | |,! The return of BOOL can be assigned directly to BOOL:
Return - (BOOL)isBold {return [self fontTraits] & NSFontBoldTrait; } - (BOOL)isValid { return [self stringValue]; } // Correct - (BOOL)isBold {return ([self fontTraits] & NSFontBoldTrait)? YES : NO; BOOL - (BOOL)isValid {return [self stringValue]! = nil; } - (BOOL)isEnabled { return [self isValid] && [self isBold]; }Copy the code
BOOL can be converted to _Bool and BOOL, but not to Boolean.
The use of the ARC
Unless we want to be compatible with some antique machines and operating systems, there’s no reason to stop using ARC. In the latest version of Xcode, ARC is automatically turned on, so just use it.
Do not use accessor methods to access instance variables in init and dealloc
When the init and Dealloc methods are executed, the runtime environment of the class is not in a normal state, and accessing variables using access methods can lead to unexpected results, so instance variables should be accessed directly within these methods.
- (instanceType)init {self = [super init]; if (self) { _bar = [[NSMutableString alloc] init]; } return self; } - (void)dealloc { [_bar release]; [super dealloc]; } // error, do not access method access - (instanceType)init {self = [super init]; if (self) { self.bar = [NSMutableString string]; } return self; } - (void)dealloc { self.bar = nil; [super dealloc]; }Copy the code
Release resources in a defined order
At the end of the life cycle of a class or Controller, there is often some cleanup work to be done, such as freeing resources, stopping threads, etc., which should be released in the same order as they were initialized or defined. This is done to make it easier to find errors during debugging and to prevent omissions.
Make sure that NSString is copied on assignment
NSString is very common, and when it is passed or assigned, it should be copied. This prevents the String value from being modified by other objects without your knowledge.
- (void)setFoo:(NSString *)aFoo {
_foo = [aFoo copy];
}
Copy the code
Use syntax sugar for NSNumber
Generating NSNumber objects using syntactic sugar with the @ symbol makes the code much cleaner:
NSNumber *fortyTwo = @42;
NSNumber *piOverTwo = @(M_PI / 2);
enum {
kMyEnum = 2;
};
NSNumber *myEnum = @(kMyEnum);
Copy the code
Nil checks
Since sending commands to nil objects in Objective-C doesn’t throw an exception or cause a crash, it’s just a complete “do nothing,” so use nil only in programs for logical checks.
Also, don’t use forms such as nil == Object or Object == nil.
// If (! objc) { ... } // error, do not use the form nil == Object if (nil == objc) {... }Copy the code
Property is thread-safe
When defining a property, the compiler automatically generates thread-safe access methods (Atomic), but this can greatly degrade performance, especially for properties that require frequent access and can be wasteful. So if you define a property that does not require thread protection, remember to manually add the property keyword nonatomic to de-optimize the compiler.
The use of dot grammar
Do not use dot point syntax to call methods, only to access properties. This is to prevent code readability problems.
NSString *oldName = myObject.name; myObject.name = @"Alice"; // error, do not call method NSArray *array = [NSArray arrayWithObject:@"hello"]; NSUInteger numberOfItems = array.count; array.release;Copy the code
The Delegate uses weak references
A class’s Delegate object usually refers to the class itself, which can easily cause reference loops, so the class’s Delegate property should be set to weak references.
/** delegate */
@property (nonatomic, weak) id <IPCConnectHandlerDelegate> delegate;
Copy the code
Swift code specification
A, named
Type 1.
- Type names (such as struct, enum, class, typedef, associatedType, protocol, etc.) are named using the big camel name.
- Variables and constants are named with the small hump.
enum Planet {
case mercury, venus, earth, mars, jupiter, saturn, uranus, neptune
}
struct Person {
var mobileNo: String
}
Copy the code
2. The agreement
According to Apple interface design guidelines, protocol names are nouns when they describe what something is, such as Collection, WidgetFactory. If the agreement name is used to describe capabilities, it should end with -ing, -able, or -ible, e.g. Equatable, Resizing.
3. The class prefix
- Classes (classes, structures) in Swift set the module to the default namespace at compile time, so there is no need to add prefixes to distinguish classes, such as RW.
- If you are worried about two names from different modules colliding, you can add the module name to distinguish between them. Be careful not to abuse the module name and use it only in situations where there is a possibility of conflict or confusion. Such as:
import SomeModule
let myClass = SomeModule.UsefulClass(a)Copy the code
4. Name parameters
entrust
When defining a delegate method, the first unnamed parameter should be the delegate data source. Correct code:
func namePickerView(_ namePickerView: NamePickerView.didSelectName name: String)
func namePickerViewShouldReload(_ namePickerView: NamePickerView) -> Bool
Copy the code
Error code:
func didSelectName(namePicker: NamePickerViewController.name: String)
func namePickerShouldReload(a) -> Bool
Copy the code
The generic
Generic class parameters should be descriptive and follow the camel nomenclature. If a parameter name has no specific meaning, you can use traditional single-uppercase characters such as T, U, or V. Correct code:
struct Stack<Element>{ . }
func writeTo <Target: OutputStream> (to Target: inout Target)
func swap(_ a: inout T._ b: inout T)
Copy the code
Error code:
struct Stack<T>{ . }
func write<target: OutputStream> (to target: inout target)
func swap<Thing> (_ a: inout Thing._ b: inout Thing)
Copy the code
Second, code logic
1. Type inference
Use type inference whenever possible to reduce redundant type information.
let currentLocation = Location(a)Copy the code
Wrong way to write:
let currentLocation: Location = Location(a)Copy the code
2. The self
- Let the compiler infer self wherever it allows.
- Explicitly use self when setting parameters in init.
- Explicit use of self in non-escaping closures.
- Use self to avoid naming conflicts. Ex. :
class BoardLocation {
let row: Int, column: Int
init(row: Int.column: Int) {
self.row = row
self.column = column
let closure = {
print(self.row)
}
}
}
Copy the code
3. The constant
- Class constants should be declared in the type as
static
. usestatic
Modifier constants allow them to be referenced without instantiating the type. - With the exception of singletons, global constants should be avoided whenever possible.
- Use the let keyword to define constants, use the var keyword to define variables, and use constants if the value of the variable will not change in the future.
struct PhysicsModel {
static var speedOfLightInAVacuum = 299 _792_458
}
class Spaceship {
static let topSpeed = PhysicsModel.speedOfLightInAVacuum
var speed: Double
func fullSpeedAhead(a) {
speed = Spaceship.topSpeed
}
}
Copy the code
4. Computed type attributes
- Return a simple Computed property when you only need to inherit getter methods.
Correct code:
class Example {
var age: UInt32 {
return arc4random()
}
}
Copy the code
Error code:
class Example {
var age: UInt32 {
get {
return arc4random()
}
}
}
Copy the code
- If you add a set or didSet to a property, then you should explicitly provide the GET method.
class Person {
var age: Int {
get {
return Int(arc4random())
}
set {
print("That's not your age.")}}}Copy the code
5. The singleton
Swift singletons are simple. Swift Runtime ensures that singletons are created and accessed in a thread-safe manner:
class ControversyManager {
static let sharedInstance = ControversyManager()}Copy the code
Singletons usually only need to access the static property of “sharedInstance” unless you have a compelling reason to rename it. Be careful not to use static or global functions to access your singleton.
6. Error handling
Use do/try/catch mechanisms instead of try! And try?
7. An optional value
- Used when declaring that a function argument can be nil
?
- When you determine that a variable is not nil when used, you add it
!
8. Extend the declaration cycle
Extend the life cycle with the [weak self] and Guard let strongSelf = self else {return} modes. Weak self is better than unowned self. Correct code:
resource.request().onComplete { [weak self] response in
guard let strongSelf = self else { return }
let model = strongSelf.updateModel(response)
strongSelf.updateUI(model)
}
Copy the code
Error code:
// might crash if self is released before response returns
resource.request().onComplete { [unowned self] response in
let model = self.updateModel(response)
self.updateUI(model)
}
// deallocate could happen between updating the model and updating UI
resource.request().onComplete { [weak self] response in
let model = self?.updateModel(response)
self?.updateUI(model)
}
Copy the code
Third, code structure
1. The comments
- Use Xcode8’s built-in annotation function, shortcut keys
Option+Command+/
- use
// MARK:
Separator code (similar to OC#pragma mark
)
2. The indentation
Follow Xcode’s built-in indentation format
Type 3.
Swift primitives are preferred, and methods provided by Objective-C can be used as needed, since Swift provides Bridges to Objective-C. Correct code:
let width = 120.0 // Double
let widthString = (width as NSNumber).stringValue // String
Copy the code
Error code:
let width: NSNumber = 120.0 // NSNumber
let widthString: NSString=width.stringValue // NSString
Copy the code
4. Protocol consistency
When an object wants to implement protocol consistency, it is recommended to use extension to isolate the set of methods in the extension protocol. This allows related methods and protocols to be displayed centrally and simplifies the process of classes supporting a protocol and implementing related methods. Correct code:
class MyViewcontroller: UIViewController {
/ / method
}
extension MyViewcontroller: UITableViewDataSource {
/ / UITableViewDataSource method
}
extension MyViewcontroller: UIScrollViewDelegate {
/ / UIScrollViewDelegate method
}
Copy the code
Error code:
class MyViewcontroller: UIViewController.UITableViewDataSource.UIScrollViewDelegate {
// All methods
}
Copy the code
5. Good class definitions
- Properties, variables, constants, and parameters are declared with a space after: and no space before:, such as x: Int, and Circle: Shape
- Multiple variables/data structures can be defined on the same line for the same purpose and context.
- Indent getter, setter definition and property observer definition.
- No need to add
internal
This is the default modifier. There is no need to add access modifiers when overriding a method. - For classes that are not intended to be inherited
final
The modifier
final class Circle: Shape {
var x: Int, y: Int
var radius: Double
var diameter: Double{
get {
returnradius * 2
}
set {
radius=newValue/2}}init(x: Int.y: Int.radius: Double) {
self.x = x
self.y = y
self.radius = radius
}
convenience init(x: Int.y: Int.diameter: Double) {
self.init(x: x, y: y, radius: diameter/2)}func describe(a) -> String{
return"I am a circle at\(centerString())with an area of\(computeArea())"
}
override func computeArea(a) -> Double{
return M_PI * radius * radius
}
private func centerString(a)->String{
return "(\(x).\(y))"}}Copy the code
6. Control the process
- Loop through for-in expressions instead of while expressions. Correct code:
for _ in 0..<3 {
print("Hello three times")}for(index, person) in attendeeList.enumerate() {
print("\(person)is at position #\(index)")}for index in 0.stride(from: 0, to: items.count, by: 2) {
print(index)
}
for index in (0.3).reverse() {
print(index)
}
Copy the code
Error code:
var i=0
while i<3 {
print("Hello three times")
i+ =1
}
var i=0
while i<3 {
let person = attendeeList[i]
print("\(person)is at position #\(i)")
i+ =1
}
Copy the code
- Break is not explicitly used in the Switch module.
7. Golden path
When coding encounters conditional judgments, the distance to the left is the golden or happy path, because the shorter the path, the faster the speed. Do not nest if loops; multiple return statements are ok. That’s what Guard was born for. Correct code:
func computeFFT(context: Context? .inputData: InputData?). throws -> Frequencies {
guard let context = context else {throwFFTError.NoContext }
guard let inputData = inputData else { throwFFTError.NoInputData }
/ / calculate frequencies
return frequencies
}
Copy the code
Error code:
func computeFFT(context: Context? .inputData: InputData?). throws -> Frequencies {
if let context = context {
if let inputData = inputData {
/ / calculate frequencies
return frequencies
} else {
throwFFTError.NoInputData}}else {
throwFFTError.NoContext}}Copy the code
When multiple conditions require guard or if let unpacking, compound statements can be used to avoid nesting.
guard let number1=number1, number2=number2, number3=number3 else{
fatalError("impossible")}/ / processing number
Copy the code
8. Syntactic sugar
// Use type annotations for empty data and dictionaries
var names: [String] = []
var lookup: [String: Int] = [:]
var deviceModels: [String]
var employees: [Int:String]
var faxNumber: Int?
Copy the code
Function of 9.
Free functions are not attached to any class or type and should be used sparingly. Correct code:
let sorted = items.mergeSort() // Discoverability
rocket.launch() / / readability
Copy the code
Error code:
let sorted = mergeSort(items)// Not easy to see
launch(&rocket)
Copy the code
Natural free function:
let value = max(x,y,z) // another free function that feels natural
Copy the code