iOS Extension - Objective-C Development Programming Specification

Keywords: iOS Attribute Mac xcode Google

This article is mainly reproduced from: Objective-C-Coding-Guidelines-In-Chinese

Objective-C coding specification, content from Apple, Google document translation, your coding experience and summary of other information.

Summary

Objective-C is an object-oriented dynamic programming language that is mainly used to write iOS and Mac applications.Both Apple and Google have a good summary of the coding specifications for Objective-C:

This paper mainly combines the translation of the above documents, the author's own programming experience and other relevant information, and summarizes a common coding specification for the company.

Two-code format

2.1 Use spaces instead of tabs

Do not use the Tab key in your project, use spaces to indent.Set both tab and autoindent to 4 spaces in Xcode > Preferences > Text Editing.(Google's standard is to use two spaces for indentation, but the default Xcode setting is recommended here.)

2.2 Maximum length per line

Similarly, setting the maximum line length to 80 in Xcode > Preferences > Text Editing > Page guide at column: will cause readability problems if one line is too long.

Writing 2.3 Functions

A typical Objective-C function should look like this:

- (void)writeVideoFrameWithData:(NSData *)frameData timeStamp:(int)timeStamp {
    ...
}

There should be a space between - and (void). The first brace {is at the end of the line where the function is located, and there should also be a space.(Our C language specification requires the first curly bracket to be on a separate line, but considering the long OC function name and the style of the Apple SDK code, the curly bracket should be placed at the end of the line.)

If a function has exceptionally many parameters 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;

In a row, if the first paragraph name is too short, subsequent names can be indented in Tab length (four spaces):

- (void)short:(GTMFoo *)theFoo
        longKeyword:(NSRect)theRect
  evenLongerKeyword:(float)theInterval
              error:(NSError **)theError {
    ...
}

2.4 Function Calls

Function calls are written in much the same format, and can be written on one or more lines depending on the length of the function:

//Write on one line
[myObject doFooWith:arg1 name:arg2 error:arg3];

//Write on separate lines, as per':'alignment
[myObject doFooWith:arg1
               name:arg2
              error:arg3];

//The first paragraph can be indented later if its name is too short
[myObj short:arg1
          longKeyword:arg2
    evenLongerKeyword:arg3
                error:arg4];

The following is incorrect:

//Errors either written on one line or all branches
[myObject doFooWith:arg1 name:arg2
              error:arg3];
[myObject doFooWith:arg1
               name:arg2 error:arg3];

//Error, as per':'To align instead of keywords
[myObject doFooWith:arg1
          name:arg2
          error:arg3];

2.5 @public and @private Tags

The @public and @private tags should be indented with a space:

@interface MyClass : NSObject {
 @public
  ...
 @private
  ...
}
@end

2.6 Protocol (Protocols)

When writing an agreement, note that there is no space between the protocol and the type name enclosed in <>, such as IPCConnectHandler()<IPCPreconnector Delegate>. This rule applies to all writing 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 

2.7 Closure (Blocks)

Depending on the length of the block, there are different writing rules:

  • Shorter block s can be written on one line.
  • The right parenthesis} of the block should be aligned to the first non-empty character in the line where the block is called, if displayed on a separate line.
  • The code inside the block is indented by four spaces.
  • If the block is too large, it should be declared as a variable to use.
  • There is no space between ^ and (between ^ and {, right parenthesis in the parameter list) and {.
//Shorter block Write on one line
[operation setCompletionBlock:^{ [self onOperationDone]; }];

//Branched Written block,Internal use of 4-space indentation
[operation setCompletionBlock:^{
    [self.delegate newDataAvailable];
}];

//Use C language API Called block Follow the same writing rules
dispatch_async(_fileIOQueue, ^{
    NSString* path = [self sessionFilePath];
    if (path) {
      // ...
    }
});

//Longer block Keyword can be indented and written on a new line, note block Right parenthesis of'}'And invocation block First non-empty character alignment of that line of code
[[SessionService sharedService]
    loadWindowWithCompletionBlock:^(SessionWindow *window) {
        if (window) {
          [self windowDidLoad:window];
        } else {
          [self errorLoadingWindow];
        }
    }];

//Longer block Parameter lists can also be indented and written on new lines
[[SessionService sharedService]
    loadWindowWithCompletionBlock:
        ^(SessionWindow *window) {
            if (window) {
              [self windowDidLoad:window];
            } else {
              [self errorLoadingWindow];
            }
        }];

//Huge block Should be defined separately as variable use
void (^largeBlock)(void) = ^{
    // ...
};
[_operationQueue addOperationWithBlock:largeBlock];

//Use multiple in one call block,Notice that they don't pass through functions like that':'Aligned, but indented by four spaces at the same time
[myObject doSomethingWith:arg1
    firstBlock:^(Foo *a) {
        // ...
    }
    secondBlock:^(Bar *b) {
        // ...
    }];

2.8 Grammatical Sugars for Data Structure

The data structures such as NSArray and NSDictionary should be constructed with more readable grammatical sugars instead of using the lengthy alloc,init methods.

If the construction code is written on one line, a space needs to be left at both ends of the brackets to distinguish the constructed elements from the construction syntax:

//Correct, in grammatical sugar's"[]"perhaps"{}"Space at both ends
NSArray *array = @[ [foo description], @"Another String", [bar description] ];
NSDictionary *dict = @{ NSForegroundColorAttributeName : [NSColor redColor] };

//Incorrect, leaving no space reduces readability
NSArray* array = @[[foo description], [bar description]];
NSDictionary* dict = @{NSForegroundColorAttributeName: [NSColor redColor]};

If the construction code is not written in one line, the construction element needs to be indented with two spaces, the right parenthesis] or} on a new line, aligned with the first non-empty character in the line calling the grammar sugar:

NSArray *array = @[
  @"This",
  @"is",
  @"an",
  @"array"
];

NSDictionary *dictionary = @{
  NSFontAttributeName : [NSFont fontWithName:@"Helvetica-Bold" size:12],
  NSForegroundColorAttributeName : fontColor
};

When constructing a dictionary, the Key and Value of the dictionary are aligned with the middle colon: each has a space, and when writing on multiple lines, the Value can also be aligned:

//Correct, colon':'Leave a space before and after
NSDictionary *option1 = @{
  NSFontAttributeName : [NSFont fontWithName:@"Helvetica-Bold" size:12],
  NSForegroundColorAttributeName : fontColor
};

//Correct, according to Value To align
NSDictionary *option2 = @{
  NSFontAttributeName :            [NSFont fontWithName:@"Arial" size:12],
  NSForegroundColorAttributeName : fontColor
};

//Error, there should be a space before the colon
NSDictionary *wrong = @{
  AKey:       @"b",
  BLongerKey: @"c",
};

//Error, each element is either a single line or all written in one line
NSDictionary *alsoWrong= @{ AKey : @"a",
                            BLongerKey : @"b" };

//Error, there can only be one space before the colon, and after the colon you can consider following Value alignment
NSDictionary *stillWrong = @{
  AKey       : @"b",
  BLongerKey : @"c",
};

Three Naming Specifications

3.1 Basic Principles

3.1.1 Clear

Naming should be as clear and concise as possible, but in Objective-C, clarity is more important than conciseness.Because of Xcode's powerful auto-completion capabilities, we don't have to worry about long names.

//clear
insertObject:atIndex:

//Blurring, insert Object types and at Location property not described
insert:at:

//clear
removeObjectAtIndex:

//Blurring, remove Object type is not described, and the role of parameters is not explained
remove:
//Don't use abbreviations. Spell the whole word:

//clear
destinationSelection
setBackgroundColor:

//Not clear, don't use abbreviations
destSel
setBkgdColor:

However, some abbreviations of words are so common in Objective-C encoding that they become a specification that can be used directly in code, as listed below:

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     == Integer

Avoid ambiguities when naming methods or functions

//Ambiguous, is return sendPort still send One Port?
sendPort

//Is it ambiguous whether to return the value of a name property or display One name Actions?
displayName

3.1.2 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 collections. We cannot use count in class A and getNumber in class B.

3.2 Use prefixes

It is useful to use named prefixes if the code needs to be packaged into a Framework for other projects or if the project is very large and needs to be split into different modules.

  • Prefixes consist of uppercase abbreviations, such as the NS prefix in Cocoa representing classes in the Founation framework and the IB representing 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 contained within the class namespace itself.

  • Do not name the prefix in conflict with the Apple SDK framework.

3.3 Named Classes and Protocols (Class&Protocol)

  • The class name begins with a capital letter and should contain a noun to represent the type of object it represents, with the necessary prefixes, such as NSString, NSDate, NSScanner, NSApplication, and so on.
  • The protocol name should clearly represent the behavior it performs and be distinguished from the class name, so a protocol, such as NSCopying or NSLocking, is usually named after the ing suffix.

Some protocols contain many unrelated functions, mainly for a particular type of service. At this time, the protocol can be named directly by the class name, such as the NSObject protocol, which contains a series of methods for the id object during its life cycle.

3.4 Named Headers

The header file name of the source code should clearly indicate its functionality and what it contains:

  • If only a single class or protocol is defined in the header file, name the header file directly with the class or protocol name, such as NSLocale.h, which defines the NSLocale class.

  • If the header file defines a series of classes, protocols, and categories, use the most important class names to name the header file, such as NSString.h, which defines NSString and NSMutableString.

  • Each Framework should have a header file with the same name as the Framework that contains references to all public class headers in the Framework, such as Foundation.h

  • Framework sometimes implements class class extension in other frameworks. Such files are usually named with the extended framework name + Additions, such as NSBundleAdditions.h.

3.5 Naming Methods

Objective-C method names are usually longer, which is to make the program more readable, according to Apple* "Good method names should be read out as a sentence"*.

Methods generally begin with lowercase letters, with each subsequent word capitalized. There should be no punctuation (including underscores) in the method name with two exceptions:

  • You can start with some common capital abbreviations, such as PDF,TIFF, and so on.
  • Private methods or methods in categories can be named with an underlined prefix.

If the method means to have the object perform an action, start with a verb and name it, be careful not to use do, does, which is a redundant keyword, the verb itself is sufficiently implied:

//Verb start means to have the object perform an action
- (void)invokeWithTarget:(id)target;
- (void)selectTabViewItem:(NSTabViewItem *)tabViewItem;

If the method is to get an attribute value of an object, name the method directly with the attribute name, and be careful not to add get or other verb prefixes:

//Correct, use attribute names to name methods
- (NSSize)cellSize;

//Error, extra verb prefix added
- (NSSize)calcCellSize;
- (NSSize)getCellSize;

For methods with multiple parameters, it is important to add keywords before each parameter, which should clearly explain the role of the parameters:

//Correct, make sure each parameter has keyword modifiers
- (void)sendAction:(SEL)aSelector toObject:(id)anObject forAllCells:(BOOL)flag;

//Error, missing keywords
- (void)sendAction:(SEL)aSelector :(id)anObject :(BOOL)flag;

//Correct
- (id)viewWithTag:(NSInteger)aTag;

//Error, the role of keywords is unclear
- (id)taggedView:(int)aTag;

Do not use ands to connect two parameters, and are usually used to represent methods that perform two relatively independent operations (which should, by design, be split into two separate methods):

//Error, do not use"and"To connect parameters
- (int)runModalForDirectory:(NSString *)path andFile:(NSString *)name andTypes:(NSArray *)fileTypes;

//Correct, use"and"To represent two relatively independent operations
- (BOOL)openFile:(NSString *)fullPath withApplication:(NSString *)appName andDeactivate:(BOOL)flag; 

There are also some things to note about parameter naming for methods:

  • Similar to the method name, the first letter of the parameter is lowercase and each subsequent word is capitalized
  • Do not use such words as pointer,ptr in method names to represent pointers anymore. The type of parameter itself is sufficient to illustrate this.
  • Do not use parameter names with only one or two letters
  • Don't use abbreviations, spell out the whole word

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 *)aString

3.6 Accessor Methods

Access methods refer to the methods used to obtain and set class attribute values. Different types of attributes correspond to different access method specifications:

//Attribute is an access method paradigm for a noun
- (type)noun;
- (void)setNoun:(type)aNoun;
//Chestnuts
- (NSString *)title;
- (void)setTitle:(NSString *)aTitle;

//Attribute is a paradigm for accessing adjectives
- (BOOL)isAdjective;
- (void)setAdjective:(BOOL)flag;
//Chestnuts
- (BOOL)isEditable;
- (void)setEditable:(BOOL)flag;

//A paradigm for accessing attributes as a verb
- (BOOL)verbObject;
- (void)setVerbObject:(BOOL)flag;
//Chestnuts
- (BOOL)showsAlpha;
- (void)setShowsAlpha:(BOOL)flag;

Do not use verbs in the passive form when naming access methods:

//Correct
- (void)setAcceptsGlyphInfo:(BOOL)flag;
- (BOOL)acceptsGlyphInfo;

//Error, do not use the passive form of verbs
- (void)setGlyphInfoAccepted:(BOOL)flag;
- (BOOL)glyphInfoAccepted;

You can use the words can,should,will to help convey the meaning of an access method, but don't use do, and do:

//Correct
- (void)setCanHide:(BOOL)flag;
- (BOOL)canHide;
- (void)setShouldCloseDocument:(BOOL)flag;
- (BOOL)shouldCloseDocument;

//Error, do not use"do"perhaps"does"
- (void)setDoesAcceptGlyphInfo:(BOOL)flag;
- (BOOL)doesAcceptGlyphInfo;

Why is the get prefix not applicable in Objective-C to represent the attribute acquisition method?Because get is usually used only in Objective-C to represent functions that return values from function pointers:

//The three parameters are used as the return value of the function, so that the function name can be used"get"prefix
- (void)getLineDash:(float *)pattern count:(int *)count phase:(float *)phase;

3.7 Naming Delegate

When a specific event occurs, the object triggers its registered delegate method.Delegates are a common way of delivering messages in Objective-C.Delegates have its fixed naming paradigm.

The first parameter of a delegate method is the object that triggers it, and the first keyword is the class name of the trigger object unless the delegate method has only one parameter named sender:

//The first keyword is the class name that triggers the delegate
- (BOOL)tableView:(NSTableView *)tableView shouldSelectRow:(int)row;
- (BOOL)application:(NSApplication *)sender openFile:(NSString *)filename;

//When there is only one"sender"Class names can be omitted from parameters
- (BOOL)applicationOpenUntitledFile:(NSApplication *)sender;

Use keywords such as should,will,did, and so on, depending on when and why the delegate method triggers

- (void)browserDidScroll:(NSBrowser *)sender;

- (NSUndoManager *)windowWillReturnUndoManager:(NSWindow *)window;

- (BOOL)windowShouldClose:(id)sender;

3.8 Collection Operation Class Methods

Some objects manage a collection of other objects or elements and need to operate on the collection using methods such as Add, Delete, Check and Change. The naming paradigm of these methods is generally:

//Collection operation paradigm
- (void)addElement:(elementType)anObj;
- (void)removeElement:(elementType)anObj;
- (NSArray *)elements;

//Chestnuts
- (void)addLayoutManager:(NSLayoutManager *)obj;
- (void)removeLayoutManager:(NSLayoutManager *)obj;
- (NSArray *)layoutManagers;

Note that if the returned collection is out of order, use NSSet instead of NSArray.If you need to insert elements into a specific location, use a name similar to this:

- (void)insertLayoutManager:(NSLayoutManager *)obj atIndex:(int)index;
- (void)removeLayoutManagerAtIndex:(int)index;

If there is a pointer to a managed object in a managed collection element, set it to a weak type to prevent reference loops.

The following is a collection operation of the NSWindow class in SDK:

- (void)addChildWindow:(NSWindow *)childWin ordered:(NSWindowOrderingMode)place;
- (void)removeChildWindow:(NSWindow *)childWin;
- (NSArray *)childWindows;
- (NSWindow *)parentWindow;
- (void)setParentWindow:(NSWindow *)window;

3.9 Named Functions

Functions are still needed in many cases, for example, if an object is a singleton, functions should be used instead of class methods to perform related operations.

There are some differences in the naming and methods of functions, mainly:

  • Function names are usually prefixed with abbreviations to represent the framework within which the method resides.
  • The prefix is followed by a word in the form of a hump, with the first word capitalized.

The first word of a function name is usually a verb that indicates what the method does:

NSHighlightRect
NSDeallocateObject

If the function returns an attribute of its parameter, omit the verb:

unsigned int NSEventMaskFromType(NSEventType type)
float NSHeight(NSRect aRect)

If a function returns a value through a pointer parameter, use Get in the function name:

const char *NSGetSizeAndAlignment(const char *typePtr, unsigned int *sizep, unsigned int *alignp)

When the return type of a function is BOOL, it is named:

BOOL NSDecimalIsNotANumber(const NSDecimal *decimal)

3.10 Named properties and instance variables (Properties&Instance Variables)

Attributes are associated with the method of accessing the object, the first letter of the attribute is lowercase, and the first letter of the subsequent word is capitalized without adding a prefix.Attributes are named nouns or verbs by function:

//Noun Properties
@property (strong) NSString *title;

//Verb Properties
@property (assign) BOOL showsAlpha;

Attributes can also be named shaping adjectives, when a get method with the is prefix is usually specified to improve readability:

@property (assign, getter=isEditable) BOOL editable;

Name the instance variable with a _prefix before the variable name (some historic codes put _after), as with the named properties:

@implementation MyClass {
    BOOL _showsTitle;
}

In general, classes need to hide the details of the data store from users, so instead of defining instance methods as publicly accessible interfaces, use the @private, @protected prefix.

According to Apple, direct access to instance variables is not recommended outside the init and dealloc methods, but many people think that direct access will make your code more readable and that I use access only when I need to calculate or perform operations, which is my habit, so I don't ask for it here.

3.11 Named Constants

If you want to define a set of related constants, try using enumerations, which have the same naming rules as functions.It is recommended to use NS_ENUM and NS_OPTIONS macros to define enumeration types, see Official Adopting Modern Objective-C Article:

//Define an enumeration
typedef NS_ENUM(NSInteger, NSMatrixMode) {
    NSRadioModeMatrix,
    NSHighlightModeMatrix,
    NSListModeMatrix,
    NSTrackModeMatrix
};

//Definition bit map
typedef NS_OPTIONS(NSUInteger, NSWindowMask) {
    NSBorderlessWindowMask      = 0,
    NSTitledWindowMask          = 1 << 0,
    NSClosableWindowMask        = 1 << 1,
    NSMiniaturizableWindowMask  = 1 << 2,
    NSResizableWindowMask       = 1 << 3
};

Use const to define floating-point or single integer constants, and enumeration should take precedence if you want to define a set of related integer constants.Constants have the same naming conventions as functions:

const float NSLightGray;

Do not use the #define macro to define constants. If it is an integer constant, try using enumerations, floating-point constants, and const to define constants.#define is often used to give the compiler a decision about whether to compile a block of code, such as common:

#ifdef DEBUG

Note that macros typically defined by the compiler have a u around them, such as *u MACH_*.

3.12 Notifications

Notifications are often used to communicate messages between modules, so to best represent what has happened, the naming paradigm for notifications is:

[Class name triggering notification] + [Did | Will] + [action] + Notification

//Chestnuts:
NSApplicationDidBecomeActiveNotification
NSWindowDidMiniaturizeNotification
NSTextViewDidChangeSelectionNotification
NSColorPanelColorDidChangeNotification

Four Notes

You and I have all experienced the pain of reading code without comments. Good comments not only make it easy to read your program, but also improve the quality of your code.Note that notes are meant to be understood, not just by you.

4.1 File Comments

Every file must have a file comment, which usually contains

  • The module where the file is located
  • Author Information
  • Historical Version Information
  • Copyright Information
  • What the file contains, what it does

Chestnuts with a good file comment:

/*******************************************************************************
    Copyright (C), 2011-2013, Andrew Min Chang

    File name:     AMCCommonLib.h
    Author:        Andrew Chang (Zhang Min) 
    E-mail:        LaplaceZhang@126.com
    
    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-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

    Copyright information: 
            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. 
        
********************************************************************************/

The format of the file notes is usually not required and can be easily read, but they should be uniform throughout the project.

4.2 Code Comments

Good code should be self-documenting, but detailed comments are needed to explain the meaning of the parameters, return values, functionality, and possible side effects.

Definitions of methods, functions, classes, protocols, and categories need to be commented. Apple's standard commenting style is recommended. The advantage is that you can automatically pop up comments by alt+clicking where they are referenced.

There are many plugins that can automatically generate annotation formats, which are recommended VVDocumenter:

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.
 *
 *  @param type       Connect type the preconnector use.
 *  @param macAddress Preconnector's mac address.
 */
- (void)refreshConnectorWithConnectType:(IPCConnectType)type  Mac:(NSString *)macAddress;

/**
 *  Stop current preconnecting when application is going to background.
 */
-(void)stopRunning;

/**
 *  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

Comments on agreements and delegations should clearly state the conditions under which they are triggered:

/** Delegate - Sent when failed to init connection, like p2p failed. */
-(void)initConnectionDidFailed:(IPCConnectHandler *)handler;

If you want to reference the parameter name or method function name in the comment, use || to enclose the parameter or method to avoid ambiguity:

// Sometimes we need |count| to be less than zero.

// Remember to call |StringWithoutSpaces("foo bar baz")|

The interface methods and properties defined in the header file must be commented out!

Five Coding Styles

Everyone has their own coding style, here are some good Cocoa programming styles and points of attention.

5.1 Do not use the new method

Although the alloc init method can often be replaced with new, this can cause unexpected problems when debugging memory.The Cocoa specification is to use the alloc init method, which can confuse some readers.

5.2 Keep the Public API as concise as possible

The common interface should be designed concisely to meet the core functional requirements.Don't design an API that is rarely used, but with extremely complex parameters.If you want to define complex methods, use categories or class extensions.

5.3 #import and #include

#import is a common way of referencing header files in Cocoa. It automatically prevents duplicate referencing of files, when to use #import, and when to use #include?

  • Use #import when referring to an Objective-C or Objective-C++ header file
  • When referencing a C or C++ header file, use #include, which ensures that the referenced file provides a protected domain (#define guard).

Chestnuts:

#import <Cocoa/Cocoa.h>
#include <CoreFoundation/CoreFoundation.h>
#import "GTMFoo.h"
#include "base/basictypes.h"

Why not use #import all?The main purpose is to ensure that there are no problems when code is shared across platforms.

5.4 Root header file referencing frame

As mentioned above, each framework will have a header file with the same name as the framework, which contains all references to the interface within the framework. When using the framework, you should refer directly to this header file, not the header file of other sub-modules. Even if you only use a small part of it, the compiler will automatically complete the optimization.

//Correct, referencing root header file
#import <Foundation/Foundation.h>

//Error, do not refer to other header files in the frame separately
#import <Foundation/NSArray.h>
#import <Foundation/NSString.h>

Use of 5.5 BOOL

BOOL is defined as signed char type in Objective-C, which means that a BOOL type variable can not only represent YES(1) and NO(0) values, so never compare a BOOL type variable directly to YES:

//Error, unable to determine|great|Is the value of? YES(1),Do not put BOOL Value is directly related to YES compare
BOOL great = [foo isGreat];
if (great == YES)
  // ...be great!

//Correct
BOOL great = [foo isGreat];
if (great)
  // ...be great!

Similarly, do not return values of other types as BOOLs, in which case the BOOL variable will only be assigned the last byte of the value, which will most likely result in 0 (NO).However, some logical operators, such as &&, ||,!, return can be assigned directly to BOOL:

//Error, do not convert other types to BOOL Return
- (BOOL)isBold {
  return [self fontTraits] & NSFontBoldTrait;
}
- (BOOL)isValid {
  return [self stringValue];
}

//Correct
- (BOOL)isBold {
  return ([self fontTraits] & NSFontBoldTrait) ? YES : NO;
}

//Correctly, logical operators can be converted directly to BOOL
- (BOOL)isValid {
  return [self stringValue] != nil;
}
- (BOOL)isEnabled {
  return [self isValid] && [self isBold];
}

In addition, BOOL types can be converted to _Bool,bool, but not to Boolean.

5.6 Use ARC

There is no reason to give up using ARC unless you want to be compatible with some antique-grade machines and operating systems.In the latest version of Xcode(6.2), ARC is automatically opened, so just use it.

5.7 Do not use access methods to access instance variables in init and dealloc

When the init```dealloc method is 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 both methods.

//Correct, direct access to instance variables
- (instancetype)init {
  self = [super init];
  if (self) {
    _bar = [[NSMutableString alloc] init];
  }
  return self;
}
- (void)dealloc {
  [_bar release];
  [super dealloc];
}

//Error, do not access by access method
- (instancetype)init {
  self = [super init];
  if (self) {
    self.bar = [NSMutableString string];
  }
  return self;
}
- (void)dealloc {
  self.bar = nil;
  [super dealloc];
}

5.8 Release resources in defined order

At the end of a class or Controller's life cycle, there is often a need to do some tailing, such as freeing resources, stopping threads, etc. These tailing should be released in the same order as their initialization or definition.This is done to make it easier to find errors while debugging and to prevent omissions.

5.9 Ensure NSString is copied when assigned

NS String is very common and should be guaranteed to be copied when it is passed or assigned to prevent its value from being modified by other objects without knowing it.

- (void)setFoo:(NSString *)aFoo {
  _foo = [aFoo copy];
}

5.10 Grammatical sugar using NSNumber

Generating NSNumber objects using grammatical sugar with the @ sign can make the code simpler:

NSNumber *fortyTwo = @42;
NSNumber *piOverTwo = @(M_PI / 2);
enum {
  kMyEnum = 2;
};
NSNumber *myEnum = @(kMyEnum);

5.11 nil check

Because sending commands to nil objects in Objective-C does not throw exceptions or cause crashes, it simply "does nothing", so only nil is used in the program for logical checks.

Also, don't use forms such as nil == Object or Object == nil to judge.

//Correct, direct judgment
if (!objc) {
    ...    
}

//Error, do not use nil == Object Form
if (nil == objc) {
    ...    
}

5.12 Attribute Thread Security

When defining an attribute, the compiler automatically generates thread-safe access methods (Atomic s), but this can greatly degrade performance, especially for attributes that require frequent access.So if the properties you define do not require thread protection, remember to manually add the property keyword nonatomic to cancel the compiler's optimization.

Use of the 5.13-point grammar

Do not use dot syntax to invoke methods, only to access properties.This is to prevent code readability issues.

//Correct, use dot syntax to access attributes
NSString *oldName = myObject.name;
myObject.name = @"Alice";

//Error, do not call method with dot syntax
NSArray *array = [NSArray arrayWithObject:@"hello"];
NSUInteger numberOfItems = array.count;
array.release;

5.14 Delegate uses weak references

A Delegate object of a class usually also references the class itself, which can easily cause a reference loop, so the Delegate property of the class should be set to a weak reference.

/** delegate */
@property (nonatomic, weak) id <IPCConnectHandlerDelegate> delegate;


Posted by Savahn on Fri, 17 May 2019 07:45:09 -0700