iOS 编码规范

摘要

为了规范看准iOS编码而作。主要包含编码格式和命名规范两大章节。

在写之前对下面所用的有些词汇进行一些约定:

  • 方法 method:类,协议中国所定义的函数
  • 函数 function:

Difference between a method and a function

阅读本文的时候,心中要有作用域概念,常量,函数的命名变化主要是因为作用域的不同才体现出区别。

  • 表达式作用域
  • 块作用域
  • 函数作用域
  • 文件作用域
  • 模块作用域
  • 全局作用域

编码格式

我们使用空格缩进。你应该将编辑器设置成自动将制表符替换成空格。

行宽

尽量让你的代码保持在120列之内。

我们深知 Objective-C 是一门繁冗的语言,在某些情况下略超 120 列可能有助于提高可读性,但这也只能是特例而已,不能成为开脱。

如果阅读代码的人认为把把某行行宽保持在 120 列仍然有不失可读性,你应该按他们说的去做。

我们意识到这条规则是有争议的,但很多已经存在的代码坚持了本规则,我们觉得保证一致性更重要。

通过设置 Xcode > Preferences > Text Editing > Show page guide,来使越界更容易被发现。

方法声明和定义

- + 和返回类型之间须使用一个空格,参数列表中只有参数之间可以有空格。

方法应该像这样:

- (void)doSomethingWithString:(NSString *)theString {
  ...
}

如果一行有非常多的参数,更好的方式是将每个参数单独拆成一行。如果使用多行,将每个参数前的冒号对齐。

- (void)doSomethingWith:(GTMFoo *)theFoo
                   rect:(NSRect)theRect
               interval:(float)theInterval {
  ...
}

当第一个关键字比其它的短时,保证下一行至少有 4 个空格的缩进。这样可以使关键字垂直对齐,而不是使用冒号对齐:

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

方法调用

方法调用应尽量保持与方法声明的格式一致。当格式的风格有多种选择时,新的代码要与已有代码保持一致。

调用时所有参数应该在同一行:

[myObject doFooWith:arg1 name:arg2 error:arg3];

或者每行一个参数,以冒号对齐:

[myObject doFooWith:arg1
               name:arg2
              error:arg3];

不要使用下面的缩进风格:

[myObject doFooWith:arg1 name:arg2  // some lines with >1 arg
              error:arg3];

[myObject doFooWith:arg1
               name:arg2 error:arg3];

[myObject doFooWith:arg1
          name:arg2  // aligning keywords instead of colons
          error:arg3];

方法定义与方法声明一样,当关键字的长度不足以以冒号对齐时,下一行都要以四个空格进行缩进。

[myObj short:arg1
    longKeyword:arg2
    evenLongerKeyword:arg3];

@public@private

@public@private 访问修饰符应该左对齐。

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

@end

异常

每个 @ 标签应该有独立的一行,在 @{} 之间需要有一个空格, @catch 与被捕捉到的异常对象的声明之间也要有一个空格。

如果你决定使用 Objective-C 的异常,那么就按下面的格式。不过你最好先看看 避免抛出异常 了解下为什么不要使用异常。

@try {
  foo();
}
@catch (NSException *ex) {
  bar(ex);
}
@finally {
  baz();
}

协议名

类型标识符和尖括号内的协议名之间,不能有任何空格。

这条规则适用于类声明、实例变量以及方法声明。例如:

@interface MyProtocoledClass : NSObject<NSWindowDelegate> {
@private
  id<MyFancyDelegate> delegate_;
}
- (void)setDelegate:(id<MyFancyDelegate>)aDelegate;
@end

块(闭包)

块(block)适合用在 target/selector 模式下创建回调方法时,因为它使代码更易读。块中的代码应该缩进 4 个空格。

取决于块的长度,下列都是合理的风格准则:

  • 关括号应与块声明的第一个字符对齐。
  • 块内的代码须按 4 空格缩进。
  • 如果块太长,比如超过 20 行,建议把它定义成一个局部变量,然后再使用该变量。
  • 如果块不带参数,^{ 之间无须空格。如果带有参数,^( 之间无须空格,但 ) { 之间须有一个空格。
// The entire block fits on one line.
[operation setCompletionBlock:^{ 
    [self onOperationDone]; 
}];

// The block can be put on a new line, indented four spaces, with the
// closing brace aligned with the first character of the line on which
// block was declared.
[operation setCompletionBlock:^{
    [self.delegate newDataAvailable];
}];

// Using a block with a C API follows the same alignment and spacing
// rules as with Objective-C.
dispatch_async(fileIOQueue_, ^{
    NSString* path = [self sessionFilePath];
    if (path) {
      // ...
    }
});

// An example where the parameter wraps and the block declaration fits
// on the same line. Note the spacing of |^(SessionWindow *window) {|
// compared to |^{| above.
[[SessionService sharedService]
    loadWindowWithCompletionBlock:^(SessionWindow *window) {
        if (window) {
          [self windowDidLoad:window];
        } else {
          [self errorLoadingWindow];
        }
    }];

// An example where the parameter wraps and the block declaration does
// not fit on the same line as the name.
[[SessionService sharedService]
    loadWindowWithCompletionBlock:
        ^(SessionWindow *window) {
            if (window) {
              [self windowDidLoad:window];
            } else {
              [self errorLoadingWindow];
            }
        }];

// Large blocks can be declared out-of-line.
void (^largeBlock)(void) = ^{
    // ...
};
[operationQueue_ addOperationWithBlock:largeBlock];

点语法

应该 始终 使用点语法来访问或者修改属性,访问其他实例时首选括号。

推荐:

view.backgroundColor = [UIColor orangeColor];
[UIApplication sharedApplication].delegate;

反对:

[view setBackgroundColor:[UIColor orangeColor]];
UIApplication.sharedApplication.delegate;

间距

  • 一个缩进使用 4 个空格,永远不要使用制表符(tab)缩进。请确保在 Xcode 中设置了此偏好。
  • 方法的大括号和其他的大括号(if/else/switch/while 等等)始终和声明在同一行开始,在新的一行结束。

推荐:

if (user.happy) {
    // Do something
    dfksfaf\fa
    fdsfafsa
} 
else {
    // Do something else
}
  • 方法之间应该正好空一行,这有助于视觉清晰度和代码组织性。在方法中的功能块之间应该使用空白分开,但往往可能应该创建一个新的方法。

    - (void)do {
      module1
      
      module2
    }
    

  • @synthesize@dynamic 在实现中每个都应该占一个新行。

条件判断

条件判断主体部分应该始终使用大括号括住来防止出错,即使它可以不用大括号(例如它只需要一行)。这些错误包括添加第二行(代码)并希望它是 if 语句的一部分时。当 if 语句里面的一行被注释掉,下一行就会在不经意间成为了这个 if 语句的一部分。此外,这种风格也更符合所有其他的条件判断,因此也更容易检查。

推荐:

if (!error) {
    return success;
}

反对:

if (!error)
    return success;

if (!error) { return success };

三目运算符

三目运算符,? ,只有当它可以增加代码清晰度或整洁时才使用。单一的条件都应该优先考虑使用。多条件时通常使用 if 语句会更易懂,或者重构为实例变量。

推荐:

result = a > b ? x : y;

反对:

result = a > b ? x = c > d ? c : d : y;

错误处理

当引用一个返回错误参数(error parameter)的方法时,应该针对返回值,而非错误变量。

推荐:

NSError *error;
if (![self trySomethingWithError:&error]) {
    // 处理错误
}

反对:

NSError *error;
[self trySomethingWithError:&error];
if (error) {
    // 处理错误
}

一些苹果的 API 在成功的情况下会写一些垃圾值给错误参数(如果非空),所以针对错误变量可能会造成虚假结果(以及接下来的崩溃)。

方法

在方法签名中,在 -/+ 符号后应该有一个空格。方法片段之间也应该有一个空格。

推荐:

- (void)setExampleText:(NSString *)text image:(UIImage *)image;

变量

变量名应该尽可能命名为描述性的。除了 for() 循环外,其他情况都应该避免使用单字母的变量名。 星号表示指针属于变量,例如:NSString *text 不要写成 NSString* text 或者 NSString * text ,常量除外。 尽量定义属性来代替直接使用实例变量。除了初始化方法(initinitWithCoder:,等), dealloc 方法和自定义的 setters 和 getters 内部,应避免直接访问实例变量。更多有关在初始化方法和 dealloc 方法中使用访问器方法的信息,参见这里

推荐:

@interface NYTSection: NSObject

@property (strong, nonatomic) NSString *headline;

@end

反对:

@interface NYTSection : NSObject {
    NSString *headline;
}

变量限定符

当涉及到在 ARC 中被引入变量限定符时, 限定符 (__strong, __weak, __unsafe_unretained, __autoreleasing) 应该位于变量类型之前,

如:__weak NSString * text

init 和 dealloc

dealloc 方法应该放在实现文件的最上面,并且刚好在 @synthesize@dynamic 语句的后面。在任何类中,init 都应该直接放在 dealloc 方法的下面。

init 方法的结构应该像这样:

- (instancetype)init {
    if (self = [super init]) {
        // Custom initialization
    }

    return self;
}

字面量

每当创建 NSStringNSDictionaryNSArray,和 NSNumber 类的不可变实例时,都应该使用字面量。要注意 nil 值不能传给 NSArrayNSDictionary 字面量,这样做会导致崩溃。

推荐:

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

反对:

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

CGRect 函数

当访问一个 CGRectxywidthheight 时,应该使用CGGeometry 函数代替直接访问结构体成员。苹果的 CGGeometry 参考中说到:

All functions described in this reference that take CGRect data structures as inputs implicitly standardize those rectangles before calculating their results. For this reason, your applications should avoid directly reading and writing the data stored in the CGRect data structure. Instead, use the functions described here to manipulate rectangles and to retrieve their characteristics.

推荐:

CGRect frame = self.view.frame;

CGFloat x = CGRectGetMinX(frame);
CGFloat y = CGRectGetMinY(frame);
CGFloat width = CGRectGetWidth(frame);
CGFloat height = CGRectGetHeight(frame);

反对:

CGRect frame = self.view.frame;

CGFloat x = frame.origin.x;
CGFloat y = frame.origin.y;
CGFloat width = frame.size.width;
CGFloat height = frame.size.height;

常量

常量首选内联字符串字面量或数字,因为常量可以轻易重用并且可以快速改变而不需要查找和替换。常量应该声明为 static 常量而不是 #define ,除非非常明确地要当做宏来使用。

推荐:

static NSString * const NYTAboutViewControllerCompanyName = @"The New York Times Company";

static const CGFloat NYTImageThumbnailHeight = 50.0;

反对:

#define CompanyName @"The New York Times Company"

#define thumbnailHeight 2

枚举类型

当使用 enum 时,建议使用新的基础类型规范,因为它具有更强的类型检查和代码补全功能。现在 SDK 包含了一个宏来鼓励使用使用新的基础类型 - NS_ENUM()

推荐:

typedef NS_ENUM(NSInteger, NYTAdRequestState) {
    NYTAdRequestStateInactive,
    NYTAdRequestStateLoading
};

位掩码

当用到位掩码时,使用 NS_OPTIONS 宏。

举例:

typedef NS_OPTIONS(NSUInteger, NYTAdCategory) {
    NYTAdCategoryAutos      = 1 << 0,
    NYTAdCategoryJobs       = 1 << 1,
    NYTAdCategoryRealState  = 1 << 2,
    NYTAdCategoryTechnology = 1 << 3
};

私有属性

私有属性应该声明在类实现文件的延展(匿名的类目)中。

推荐:

@interface NYTAdvertisement ()

@property (nonatomic, strong) GADBannerView *googleAdView;
@property (nonatomic, strong) ADBannerView *iAdView;
@property (nonatomic, strong) UIWebView *adXWebView;

@end

图片命名

图片名称应该被统一命名以保持组织的完整。它们应该被命名为一个说明它们用途的驼峰式字符串,其次是自定义类或属性的无前缀名字(如果有的话),然后进一步说明颜色 和/或 展示位置,最后是它们的状态。

推荐:

  • RefreshBarButtonItem / RefreshBarButtonItem@2xRefreshBarButtonItemSelected / RefreshBarButtonItemSelected@2x
  • ArticleNavigationBarWhite / ArticleNavigationBarWhite@2xArticleNavigationBarBlackSelected / ArticleNavigationBarBlackSelected@2x.

图片目录中被用于类似目的的图片应归入各自的组中。

布尔

因为 nil 解析为 NO,所以没有必要在条件中与它进行比较。永远不要直接和 YES 进行比较,因为 YES 被定义为 1,而 BOOL 可以多达 8 位。

这使得整个文件有更多的一致性和更大的视觉清晰度。

推荐:

if (!someObject) {
}

反对:

if (someObject == nil) {
}

对于 BOOL 来说, 这有两种用法:

if (isAwesome)
if (![someObject boolValue])

反对:

if ([someObject boolValue] == NO)
if (isAwesome == YES) // 永远别这么做

如果一个 BOOL 属性名称是一个形容词,属性可以省略 “is” 前缀,但为 get 访问器指定一个惯用的名字,例如:

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

内容和例子来自 Cocoa 命名指南

单例

单例对象应该使用线程安全的模式创建共享的实例。

+ (instancetype)sharedInstance {
    static id sharedInstance = nil;

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

    return sharedInstance;
}

这将会预防有时可能产生的许多崩溃

导入

如果有一个以上的 import 语句,就对这些语句进行分组。每个分组的注释是可选的。
注:对于模块使用 @import 语法。

// Frameworks
@import QuartzCore;

// Models
#import "NYTUser.h"

// Views
#import "NYTButton.h"
#import "NYTUserView.h"

Xcode 工程

为了避免文件杂乱,物理文件应该保持和 Xcode 项目文件同步。Xcode 创建的任何组(group)都必须在文件系统有相应的映射。为了更清晰,代码不仅应该按照类型进行分组,也可以根据功能进行分组。

如果可以的话,尽可能一直打开 target Build Settings 中 "Treat Warnings as Errors" 以及一些额外的警告。如果你需要忽略指定的警告,使用 Clang 的编译特性

命名和使用原则

不允许使用自定义的缩写

推荐:

UIButton *settingsButton;

反对:

UIButton *setBut;

通用原则

清晰 Clarity

  • 命名应该尽可能的清晰简洁

  • 通常,不要使用缩写,即使是名字很长。

    setBackgroundColor: / setBkgdColor:
    destinationSelection / destSel
    

    你通常认为的缩写(abbreviation [əˌbrivɪ'eʃən]),并不能清晰的表达其你想表达的意思。不同文化和语言背景上其所代表的意思会截然不同。

  • 然而,一些通用且历史悠久的缩写,是可以使用。Acceptable Abbreviations and Acronyms

  • 避免在API中使用含糊不清的命名,比如方法名:

    Code Commentary
    sendPort 这是一个发送操作还是返回一个端口
    displayName 这是一个显示操作还是返回一个name

一致性 Consistency

  • 使用和Cocoa programmatic interfaces一致的命名,如果不确定可以参考,参考文档的头文件。

  • 一致性的重要性也体现在,一个类的多态上。同一个操作在不同类中,函数命名应当是一致的。

    i.e.- (NSInteger)tag setValue:

非自指 No Self Reference

  • 命名不应当自指。

    NSString       Good.
    NSStringObject     Self-referential.
    
  • 常量/枚举是个例外,Constants应当能自己表达自身意思。

前缀 Prefixes

Objective-C没有命名空间,Prefixes一定程度上用作命名空间。解决命名冲突。

  • prefix由两个或者三个大写字母构成。
  • prefix用于定义classes、protocols、functions、constants和typedef structures中时候。
  • 不要用在定义methods,方法已经存在于类的命名空间,也不要用在 fields定义中。

类和协议的命名

一个类命名应当包含一个名词(noun)能够清晰的表示类。也应该有合适的prefix。Foundation和Frameworks都是很好的例子。

协议(protocols)的命名应当和它所包含的一组行为相符合。

  • 大部分协议中的方法,不应该和特定的类关联(是一组行为抽象)。协议和类的命名不应该让人产生困惑。一个通用的做法是协议用动名词(gerund[^5] ..ing)形式:

    代码 说明
    NSLocking Good.
    NSLock Poor(像是一个类)
  • 有些协议包含一些不相关的methods(原则上应当分成若干小协议)。

    NSObject

方法命名 Nameing Methods

本节讨论方法命名。

通用规则

在命名方法的时候,有一些通用的指导方针需要遵守:

  • 小写字母开头之后的单词首字母大写(小驼峰式命名),不需要前缀。有两个例外:

    • 当方法是well-known acronym 开头的时候字母不小写。
    • 在命名私有方法或者分组一类方法的时候可以带前缀。
  • 当方法表示一个动作(action)的时候,方法名动词(verb)开头。

    - (void)invokeWithTarget:(id)target;
    - (void)selectTabViewItem:(NSTabViewItem *)tabViewItem
    

    不要使用“do”或者”does“作为方法的一部分,因为助动词[^6](auxiliary verbs)很少有实际意思。同样,不要在动词后面添加没用的副词[^7]和形容词。

  • 如果方法返回一个receiver的属性,方法名字紧跟attribute之后。不要使用“get”,除非间接的返回一个或者多个值

    - (NSSize)cellSize;   ✔️
    - (NSSize)calcCellSize;
    - (NSSize)getCellSize;
    
  • 方法不可忽略lable

  • 参数前面应当有描述其意的单词

    - (id)viewWithTag:(NSInteger)aTag;  ✔️
    - (id)taggedView:(int)aTag;
    
  • 在参数label中不要使用“and”

  • 如果方法描述两个分开的action,用“and”连接

    - (BOOL)openFile:(NSString *)fullPath withApplication:(NSString *)appName andDeactivate:(BOOL)flag;
    

访问方法 Accessor Methods

  • 属性表达式为名词:

    - (type)noun;

    - (void)setNoun:(type)aNoun;

    例如:

    - (NSString *)title;
    - (void)setTitle:(NSString *)aTitle;
    
  • 属性表达式为形容词:

    - (type)isAdjective;

    - (void)setAdjective:(BOOL)flag;

    例如:

    - (BOOL)isEditable;
    - (void)setEditable:(BOOL)flag;
    
  • 属性表达式为动词:

    - (type)verbObject;

    - (void)setVerbObject:(BOOL)flag;

    例如:

    - (BOOL)showsAlpha;
    - (void)setShowsAlpha:(BOOL)flag;
    

    动词通常用现在时。

  • 使用情态动词(modal verbs)像“can","should","will",使命名更加清晰,但是不要使用do/does。

    - (void)setCanHide:(BOOL)flag;
    - (BOOL)canHide;
    - (void)setShouldCloseDocument:(BOOL)flag;
    - (BOOL)shouldCloseDocument;
    
    - (void)setDoesAcceptGlyphInfo:(BOOL)flag;
    - (BOOL)doesAcceptGlyphInfo;
    
  • 仅仅在间接返回对象/值的时候使用“get”,

    - (void)getLineDash:(float *)pattern count:(int *)count phase:(float *)phase;
    NSBezierPath.
    

委托方法 Delegate Methods

委托方法是指当确定事件发生的时候调用相应的方法的方法。委托方法有特有的格式,data source 也遵循这一格式。

  • 方法名字以发送消息的类开始。

    - (BOOL)tableView:(NSTableView *)tableView shouldSelectRow:(int)row;
    - (BOOL)application:(NSApplication *)sender openFile:(NSString *)filename;
    

    省略前缀,且第一个字母小写。

  • 当委托方法只有一个参数的时:

    - (BOOL)applicationOpenUntitledFile:(NSApplication *)sender;
    
  • 使用“did”,“will”表示时间发生了或者将要发生。

  • “should” 询问时间是否发生。

    - (BOOL)windowShouldClose:(id)sender;
    

方法参数

  • 方法参数不允许出现 point、ptr 、btn等缩写。

私有方法

  • 是有方法不允许下划线开头。
  • 如果要指明类型可以添加前缀sp_xxxxx.

函数命名

当可以使用class methods & singleton 实现操作时,优先使用function实现。

  • 函数命名规则遵从方法的命名规则,但是有一些区别:

    • 函数开头要添加prefix。
    • 首字母大写。
  • 大部分函数以动词(verb)开头,描述其行为:

    NSHighlightRect
    NSDeallocateObject
    

当函数是获取属性的时候,遵循如下规则:

  • 如果函数返回的是其第一个参数的某一属性则省略动词。

    unsigned int NSEventMaskFromType(NSEventType type)
    float NSHeight(NSRect aRect)
    
  • 如果函数是通过引用返回,则需要使用Get

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

属性(property)和常量

此节描述声明属性、instance变量、常量、通知。

声明属性和实例变量

  • 属性命名和属性访问命名一样。

  • 属性尽可能减少声明属性。

  • 如果属性对外是readonly的属性声明中必须体现。

    @property (strong, readonly) NSString *title;
    

常量

常量作用于常常跨模块,所以命名空间尤为重要。

常量声明使用const不允许使用#define

枚举常量

枚举常量定义必须指定类型, 推举使用NS_ENUM

typedef NS_ENUM(NSUInteger, <#MyEnum#>) {
    <#MyEnumValueA#>,
    <#MyEnumValueB#>,
    <#MyEnumValueC#>,
};

用const定义常量

const 常量命名参考function命名

Notifications命名

格式:

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

example:
NSApplicationDidBecomeActiveNotification
NSWindowDidMiniaturizeNotification
NSTextViewDidChangeSelectionNotification
NSColorPanelColorDidChangeNotification

参考

[1] 纽约时报 移动团队 Objective-C 规范指南
[2] Objective-C 风格指南
[3] Coding Guidelines for Cocoa
[4] 自指
[5] 动名词
[6] 助动词
[7] 副词

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,402评论 6 499
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,377评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,483评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,165评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,176评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,146评论 1 297
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,032评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,896评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,311评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,536评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,696评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,413评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,008评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,659评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,815评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,698评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,592评论 2 353

推荐阅读更多精彩内容

  • 一.代码命名 一般性原则 最好是既清晰又简短,但不要为简短而丧失清晰性。 例如:removeObject:AtIn...
    睡不完懒觉阅读 1,777评论 0 16
  • Object-C 开发代码规范概要Object-C是一门面向对象的动态编程语言,主要用于编写IOS和MAC应用程序...
    克鲁德李阅读 534评论 0 1
  • 注:本文转载自http://www.cocoachina.com/ios/20150908/13335.html,...
    Sevenuncle阅读 558评论 0 0
  • 面试被问到公司编码规范问题,感觉有很多东西,但是不知道该怎么说出来,今天突然找到 李明杰 老师的一份编码规范。重新...
    Dombo_Y阅读 967评论 1 2
  • 作为威海人是一件非常幸福的事,中国海文学院总经理敏子老师带着导师团队一行5人到威海巨献《在关系中修行———界限...
    美乐泓予阅读 172评论 0 0