《禅与Objective—C编程艺术》的github地址:https://github.com/oa414/objc-zen-book-cn#swift
1. if (nil == myValue) { ...nil放左边就算少敲一个=也不会被赋值
2.条件语句多用return增加可读性,降低复杂度
3.使用长的,描述性的变量名
4.常量用 static NSString *const name = value; 不要用宏定义
5.不要将nil传进NSArray和NSDictionary,会导致崩溃
6.
NSArray *names = @[@"Brian", @"Matt", @"Chris", @"Alex", @"Steve", @"Paul"];
NSDictionary *productManagers = @{@"iPhone" : @"Kate", @"iPad" : @"Kamal", @"Mobile Web" : @"Bill"};
NSNumber *shouldUseLiterals = @YES;
NSNumber *buildingZIPCode = @10018;
7.这意味着申请分配内存和初始化被分离成两步,alloc 和 init。
alloc 负责创建对象,这个过程包括分配足够的内存来保存对象,写入 isa 指针,初始化引用计数,以及重置所有实例变量。
init 负责初始化对象,这意味着使对象处于可用状态。这通常意味着为对象的实例变量赋予合理有用的值。
8.在你希望提供你自己的初始化函数的时候,你应该遵守这三个步骤来保证获得正确的行为:
定义你的 designated initializer,确保调用了直接超类的 designated initializer。
重载直接超类的 designated initializer。调用你的新的 designated initializer。
为新的 designated initializer 写文档。
- (id)initWithNews:(ZOCNews *)news
{
// call to the immediate superclass's designated initializer (调用直接超类的 designated initializer)
self = [super initWithNibName:nil bundle:nil];
if (self) {
_news = news;
}
return self;
}
// Override the immediate superclass's designated initializer (重载直接父类的 designated initializer)
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
// call the new designated initializer
return [self initWithNews:nil];
}
@end
9.单例
如果可能,请尽量避免使用单例而是依赖注入。 然而,如果一定要用,请使用一个线程安全的模式来创建共享的实例。对于 GCD,用 dispatch_once() 函数就可以咯。
+ (instancetype)sharedInstance
{
static id sharedInstance = nil;
static dispatch_once_t onceToken = 0;
dispatch_once(&onceToken, ^{
sharedInstance = [[self alloc] init];
});
return sharedInstance;
}
10.有一个例外:永远不要在 init 方法(以及其他初始化方法)里面用 getter 和 setter 方法,你应当直接访问实例变量
11.点符号
当使用 setter getter 方法的时候尽量使用点符号。应该总是用点符号来访问以及设置属性。
例子:
view.backgroundColor = [UIColor orangeColor];
[UIApplication sharedApplication].delegate;
不要这样:
[view setBackgroundColor:[UIColor orangeColor]];
UIApplication.sharedApplication.delegate;
12.任何可以用一个可变的对象设置的((比如 NSString,NSArray,NSURLRequest))属性的内存管理类型必须是 copy 的。
13.永远不要在你的私有方法前加上 _ 前缀。这个前缀是 Apple 保留的。不要冒重载苹果的私有方法的险。
14.我们应该要在我们的 category 方法前加上自己的小写前缀以及下划线,比如- (id)zoc_myCategoryMethod。 这种实践同样被苹果推荐。
14.
NSNotification
当你定义你自己的 NSNotification 的时候你应该把你的通知的名字定义为一个字符串常量,就像你暴露给其他类的其他字符串常量一样。你应该在公开的接口文件中将其声明为 extern 的, 并且在对应的实现文件里面定义。
因为你在头文件中暴露了符号,所以你应该按照统一的命名空间前缀法则,用类名前缀作为这个通知名字的前缀。
同时,用一个 Did/Will 这样的动词以及用 "Notifications" 后缀来命名这个通知也是一个好的实践。
// Foo.h
extern NSString * const ZOCFooDidBecomeBarNotification
// Foo.m
NSString * const ZOCFooDidBecomeBarNotification = @"ZOCFooDidBecomeBarNotification”;
15.推荐:
if (user.isHappy) {
//Do something
}
else {
//Do something else
}
16.
关于 pragma
如果你知道你的代码不会导致内存泄露,你可以通过加入这些代码忽略这些警告
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
[myObj performSelector:mySelector withObject:name];
#pragma clang diagnostic pop
注意我们是如何在相关代码上下文中用 pragma 停用 -Warc-performSelector-leaks 检查的。这确保我们没有全局禁用。如果全局禁用,可能会导致错误。
17.
self 的循环引用
当使用代码块和异步分发的时候,要注意避免引用循环。 总是使用 weak 来引用对象,避免引用循环。(译者注:这里更为优雅的方式是采用影子变量@weakify/@strongify 这里有更为详细的说明) 此外,把持有 block 的属性设置为 nil (比如self.completionBlock = nil) 是一个好的实践。它会打破 block 捕获的作用域带来的引用循环。
例子:
__weak __typeof(self) weakSelf = self;
[self executeBlock:^(NSData *data, NSError *error) {
[weakSelf doSomethingWithData:data];
}];
不要这样:
[self executeBlock:^(NSData *data, NSError *error) {
[self doSomethingWithData:data];
}];
多个语句的例子:
__weak __typeof(self)weakSelf = self;
[self executeBlock:^(NSData *data, NSError *error) {
__strong __typeof(weakSelf) strongSelf = weakSelf;
if (strongSelf) {
[strongSelf doSomethingWithData:data];
[strongSelf doSomethingWithData:data];
}
}];
不要这样:
__weak __typeof(self)weakSelf = self;
[self executeBlock:^(NSData *data, NSError *error) {
[weakSelf doSomethingWithData:data];
[weakSelf doSomethingWithData:data];
}];