Objective-C规范建议


没有规矩不成方圆。说说我比较推崇的代码规范。求同存异,别的规范也是可取的,具体问题具体分析。

工程结构

  • 为整个工程创建 workspace

  • 合理的工程目录结构。

    • Core:通用的机制实现类:统一的任务管理,模块管理,服务管理。

    • General:公用类和方法,包括工程内基类(Base),公用Category,公用UI组件(CustomUI),公用辅助方法(Helper)和宏定义(Macro)。

    • Vendors:第三方库。不建议将三方库直接添加进工程,建议使用cocoapods管理。

    • 先按业务划分,再按照MV-X来划分。方便解耦,模块化。
      将TableViewCell放在View目录,把具体的ViewController放在Controller目录,图片等资源放到Resource目录,工具类放到Utils目录。


头文件

#import的顺序按照:系统类、第三方类、自己类 ( 或者按照字母排序)

 #import <系统库> 
 #import <系统库> 
 
 #import <第三方库> 
 #import <第三方库> 
 
 #import “其他类”

常量

  • 常量用static,不使用#define
 
static NSString * const AFURLSessionManagerLockName = @"com.alamofire.networking.session.manager.lock";

static NSUInteger const AFMaximumNumberOfAttemptsToRecreateBackgroundSessionUploadTask = 3;
  • 命名

若常量局限于某“编译单元”(translation unit,也就是“实现文件”,implementation file)之内,则在前面加字母k;

若常量在类之外可见,则通常以类名为前缀。

static NSString * const AFURLSessionManagerLockName = @"com.alamofire.networking.session.manager.lock";

NSString * const kTTTStrikeOutAttributeName = @"TTTStrikeOutAttribute";
  • 声明Cell的重用

    字符k+cell的名称+identifier

static NSString *const kQuestionCellIdentifier = @"kQuestionCellIdentifier";
  
  • const声明字符串提供外部使用

h声明m实现且让其他的类用使用。如果导入是UIKit类就使用UIKIT_EXTERN,如果是Founction使用关键词FOUNDATION_EXTERN。

  
//h声明
  
FOUNDATION_EXPORT NSString * const AFNetworkingReachabilityDidChangeNotification;


//m实现
  
NSString * const AFNetworkingReachabilityDidChangeNotification = @"com.alamofire.networking.reachability.change";

  • Notifications
[Name of associated class] + [Did | Will] + [UniquePartOfName] + Notification

例如:

NSApplicationDidBecomeActiveNotification
NSWindowDidMiniaturizeNotification
NSTextViewDidChangeSelectionNotification
NSColorPanelColorDidChangeNotification
  • Exceptions
[Prefix] + [UniquePartOfName] + Exception

例如:

NSColorListIOException
NSColorListNotEditableException
NSDraggingException
NSFontUnavailableException
NSIllegalSelectorException

对于#define宏命名

单词全部的大写,单词之间用_分割。

#define RCT_EXPORT_SHADOW_PROPERTY(name, type) \
+ (NSArray<NSString *> *)propConfigShadow_##name { return @[@#type]; }


枚举类型

使用NS_ENUM、NS_OPTIONS语法,不使用enum语法(除非c语言),新的语法有更强的类型检查和代码补全。

typedef NS_ENUM(NSInteger, NetworkStatus) {
    // Apple NetworkStatus Compatible Names.
    NotReachable = 0,
    ReachableViaWiFi = 2,
    ReachableViaWWAN = 1
};
typedef NS_OPTIONS(NSUInteger, SDWebImageDownloaderOptions) {
    SDWebImageDownloaderLowPriority = 1 << 0,
    SDWebImageDownloaderProgressiveDownload = 1 << 1,
    SDWebImageDownloaderUseNSURLCache = 1 << 2,
    SDWebImageDownloaderIgnoreCachedResponse = 1 << 3,
    }
    

对于NS_OPTIONS类型多值用|连接,不能用+。

NSCalendarUnitYear | NSCalendarUnitMonth | NSCalendarUnitDay

代码组织

使用#pragma mark - 进行分组

#pragma mark - Lifecycle

- (instancetype)init {}
- (void)dealloc {}
- (void)viewDidLoad {}
- (void)viewWillAppear:(BOOL)animated {}
- (void)didReceiveMemoryWarning {}

#pragma mark - Public

- (void)publicMethod {}

#pragma mark - rewrite

- (void)fatherMethod {}

#pragma mark - Private

- (void)privateMethod {}

#pragma mark - Draw
- (void)drawRect:(CGRect)rect {}

#pragma mark - Events

- (IBAction)submitData:(id)sender {}
- (void)onBtnClicked:(id)sender {}

#pragma mark - Protocol conformance
#pragma mark - UITextFieldDelegate
#pragma mark - UITableViewDataSource
#pragma mark - UITableViewDelegate

#pragma mark - Properties

- (void)setCustomProperty:(id)value {}
- (id)customProperty {}

#pragma mark - NSCopying

- (id)copyWithZone:(NSZone *)zone {}

#pragma mark - NSObject

- (NSString *)description {}

注释代码

应该尽量做到清晰可读,做到自解释。当需要注释时,注释应该更多地用来描述,为什么这样做。注释保持更新,历史的注释应该删除。

  • 可能存在问题的代码应该加上// FIXME:的注释,并详细描述(注意用半角的冒号)。

  • 需要添加逻辑的代码应该加上// TODO:,并详细描述。

  • 不是源码文件创建者修改了代码,应该在修改的代码上加上// Modified:,并写明修改人、修改时间、修改原因等信息。


命名

  • 必须尽量遵守苹果官方的命名规范,应该使用长的、描述清楚的函数名、变量名。应该使用三个字母的前缀来给类、常量进行命名。
  • 控件命名中UILabel结尾加上Label,UIImageView结尾记上ImageView等等。
@property(nonatomic,strong) UILabel  *userNameLabel;

函数(Method)

在函数签名中(函数声明或定义),在函数类型(-/+符号)后,必须有一个空格。参数之间也要有一个空格。参数的keyword不要为空。除了第一个参数,后面的参数的keyword尽量不要加with、and等连词的前缀,keyword更不应该直接用with、and。

//应该
- (void)setExampleText:(NSString *)text image:(UIImage *)image;
- (void)sendAction:(SEL)aSelector to:(id)anObject forAllCells:(BOOL)flag;
- (id)viewWithTag:(NSInteger)tag;
- (instancetype)initWithWidth:(CGFloat)width height:(CGFloat)height;
//不应该
-(void)setT:(NSString *)text i:(UIImage *)image;
- (void)sendAction:(SEL)aSelector :(id)anObject :(BOOL)flag;
- (id)taggedView:(NSInteger)tag;
- (instancetype)initWithWidth:(CGFloat)width andHeight:(CGFloat)height;
- (instancetype)initWith:(int)width and:(int)height;  // Never do this.

一般情况下,不要缩写名字,即使它们很长。少数一部分缩写是非常通用的,也有很长的使用历史。可用缩写

AbbreviationMeaning and comments
allocAllocate.
appApplication. For example, NSApp the global application object. However, “application” is spelled out in delegate methods, notifications, and so on…
calcCalculate…
deallocDeallocate.
funcFunction.
horizHorizontal.
infoInformation.
initInitialize (for methods that initialize new objects).
intInteger (in the context of a C int—for an NSInteger value, use integer).
maxMaximum.
minMinimum.
msgMessage.
nibInterface Builder archive.
pboardPasteboard (but only in constants).
rectRectangle.
RepRepresentation (used in class name such as NSBitmapImageRep)…
tempTemporary.
vertVertical.

你也可以使用下面这些在计算机行业公认的专业术语:
ASCII PDF XML HTML URL RTF HTTP TIFF JPG PNG GIF LZW ROM RGB CMYK MIDI FTP


初始化方法

返回值应该使用instancetype来代替之前的id。

- (instancetype)init {
    self = [super init];
    if (self) {
        // ...
    }
    return self;
}

单例模式

单例模式应该使用dispatch_once来保证创建时的线程安全。

static id sharedInstance = nil;

+ (instancetype)sharedInstance{
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        sharedInstance = [[self alloc] init];
    });
    return sharedInstance;
}

//重写+ allocWithZone:此方法在调用alloc时必会调用.use object initializers instead
+ (instancetype)allocWithZone:(struct _NSZone *)zone
{
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        sharedInstance = [super allocWithZone:zone];
    });
    return sharedInstance;
}
//对于单例,应该无论以何种方式创建都应该只有一份内存的, 对于ARC的创建的方法还有copy,mutableCopy,但必须遵守协议<NSCopying,NSMutableCopying> , 执行copy,MutableCopy的时候必定会执行copyWithZone,mutableCopyWithZone
- (instancetype)copyWithZone:(NSZone *)zone
{
    return sharedInstance;
}
- (instancetype)mutableCopyWithZone:(NSZone *)zone
{
    return sharedInstance;
}

//暂不考虑MRC

Error处理

当函数返回NSError的引用,调用时要根据返回值进行判断,而不是NSError的值,因为苹果的一些api会往NSError中写一些垃圾数据,如果根据NSError进行判断可能会有问题。

ARC中严重不推荐使用try catch,可能内存泄露。

NSError *error;
if (![self trySomethingWithError:&error]) {
  // Handle Error
}

黄金路径(GoldenPath)

当if判断有多层嵌套,应该尽量使用黄金路径,即不符合条件的分支先返回,这样可以避免分支嵌套。

- (void)someMethod {
    if (!condition1) {
        return;
    }
    //Do something1
    if (!condition2) {
        return;
    }
    // Do something 2
}

尤达表达式

不要使用尤达表达式。

if ([myValue isEqual:@42]) {}

三元运算符

三元运算符, ?: , 应该只在它能提高代码整洁性而且逻辑清晰的情况下使用。判断条件应该只有一个,多于一个的判断条件应该用if或临时变量来写。


#CGRect相关方法

CGRect frame = self.view.frame;

CGFloat x = CGRectGetMinX(frame);
CGFloat y = CGRectGetMinY(frame);
CGFloat width = CGRectGetWidth(frame);
CGFloat height = CGRectGetHeight(frame);
CGRect frame = CGRectMake(0.0, 0.0, width, height);

布尔值

  • 使用YES和NO来表示布尔值。
    • true和false除了CoreFoundation和C、C++代码中,不应该被使用。
    • nil被判断为NO,没有必要与nil进行比较。
    • BOOL值可以最大可以达到8位,而YES只是被设置为1,尽量不要跟YES比较。
//应该
if (someObject) {}
if (![anotherObject boolValue]) {}
//不应该
if (someObject == nil) {}
if ([anotherObject boolValue] == NO) {}
if (isAwesome == YES) {} // Never do this.
if (isAwesome == true) {} // Never do this.
  • 如果布尔类型的属性名是一个形容词,那么属性虽然可以忽略is 前缀,但最好仍提供带is前缀的getter方法。
@property (assign, getter=isEditable) BOOL editable;

使用NSInteger

Apple的UIKit等代码一般都是用的NSInteger。NSInteger在32位系统是 int,64位系统是long 。系统的代码用的是 NSInteger 的话,你使用int的话,可能不够大而造成崩溃。


分类

没有命名空间的概念。在分类中的所有方法都加上特定前缀,前缀需小写。如

NSObject+XSTest.h

@interface NSObject (XSTest)

- (BOOL)xs_isEmptyObject;

@end

这里为分类名以及分类中的方法加上XS的前缀。


#摘录
https://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/CodingGuidelines/CodingGuidelines.html
http://www.aichengxu.com/ios/7566968.htm
http://reviewcode.cn/article.html?reviewId=9
http://www.cnblogs.com/netfocus/p/3896118.html
http://www.cocoachina.com/ios/20170105/18515.html
https://github.com/objc-zen/objc-zen-book
https://juejin.im/entry/583a9eafa22b9d006c0eae3c
https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/CodingGuidelines/Articles/APIAbbreviations.html
https://www.jianshu.com/p/06cc78e8b8b6

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值