0%

这周所学新技巧(2)

博客已经两个月没有更新了,心里塞塞的。国庆节,把Objective-C高级编程:iOS与OS X多线程和内存管理看了一遍,其实这本书去年就买了,但是一直都放在柜子里冷藏中,这本书里面分析苹果源码的写的很好,里面很多东西都是从苹果官方网站摘要的,第一章”自动引用计数”大部分内容摘自Transitioning to ARC Release Notes。对于只有一点C、C++基础而直接接触iOS开发的我,开发中大部分都是从网上找资料,学的东西也是很零散,项目中需要什么就赶紧补什么,能够实现这个功能并且不出bug就行,原理方面的知道的很少,其实苹果官方网站和Xcode真的是学习的好工具,在苹果官方网站,你能系统的学到该知识点,用的时候能够说出个所以然来。在看文档的时候,对比自己项目中的代码,有违背apple开发文档的就改回来,这样对项目和自身都是有好处。所以,我打算多看看apple开发文档,记录一下那些快速消化技术点而遗漏的知识点。

#一、Don’t Use Accessor Methods in Initializer Methods and dealloc
2015/10/14
https://developer.apple.com/library/ios/documentation/Cocoa/Conceptual/MemoryMgmt/Articles/mmPractical.html
不要在init和dealloc方法里面使用访问器方法。
示例代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@interface Counter : NSObject

@property (nonatomic, retain) NSNumber *count;

@end;


- init {
    self = [super init];
    if (self) {
        _count = [[NSNumber alloc] initWithInteger:0];
    }
    return self;
}

结果我在项目中都是self.count = [[NSNumber alloc] initWithInteger:0];(相当于[self setCount:[[NSNumber alloc] initWithInteger:0]])用点语法操作对象的,所以以后在init和dealloc方法里面得调整过来。
但是文档没有说为什么不要用访问器方法。
喵神的理解是你无法确定 self 到底是不是确实调用的是你想要的实例
so上面也搜了相关问题,大家比较赞同的是:该对象不确定是否存在,很有可能会引起内存泄露(虽然我没在项目中遇到过)。

#二、A Block Should Always Be the Last Argument to a Method
2015/10/15
https://developer.apple.com/library/ios/documentation/Cocoa/Conceptual/ProgrammingWithObjectiveC/WorkingwithBlocks/WorkingwithBlocks.html#//apple_ref/doc/uid/TP40011210-CH8-SW16
建议block参数作为函数的最后一个参数。

#三、Enumeration Macros 枚举
2015/10/18
https://developer.apple.com/library/ios/releasenotes/ObjectiveC/ModernizationObjC/AdoptingModernObjective-C/AdoptingModernObjective-C.html#//apple_ref/doc/uid/TP40014150-CH1-SW1
在项目中用NS_ENUM、NS_OPTIONS表示枚举。
before:

1
2
3
4
5
6
7
8
9
10
11
12
13
enum {

UITableViewCellStyleDefault,

UITableViewCellStyleValue1,

UITableViewCellStyleValue2,

UITableViewCellStyleSubtitle

};

typedef NSInteger UITableViewCellStyle;

now:

1
2
3
4
5
6
7
8
9
10
11
typedef NS_ENUM(NSInteger, UITableViewCellStyle) {

UITableViewCellStyleDefault,

UITableViewCellStyleValue1,

UITableViewCellStyleValue2,

UITableViewCellStyleSubtitle

};

#四、NS_DESIGNATED_INITIALIZER 宏
2015/10/18
链接与第三点相同。
NS_DESIGNATED_INITIALIZER可译为指定初始化方法。我们在写初始化方法的时候,很有可能不会只有一个初始化方法(参数不同)。你是会每一个都调用一次父类的初始化方法么?还是只有一个初始化方法(即指定初始化方法)来调用父类的初始化方法,而其他的初始化方法(可理解为方便型初始化方法)就类似于金字塔一样根据不同的参数来调用该指定初始化方法?
###why ?
The designated initializer pattern helps ensure that inherited initializers properly initialize all instance variables.指定初始化模式有助于确保继承初始化时能够正确初始化所有的实例变量。

示例代码如下(来自AFHTTPSessionManager文件):
h文件:

1
2
- (instancetype)initWithBaseURL:(NSURL *)url
           sessionConfiguration:(NSURLSessionConfiguration *)configuration NS_DESIGNATED_INITIALIZER;

m文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
- (instancetype)init {
    return [self initWithBaseURL:nil];
}

- (instancetype)initWithBaseURL:(NSURL *)url {
    return [self initWithBaseURL:url sessionConfiguration:nil];
}

- (instancetype)initWithSessionConfiguration:(NSURLSessionConfiguration *)configuration {
    return [self initWithBaseURL:nil sessionConfiguration:configuration];
}

- (instancetype)initWithBaseURL:(NSURL *)url
           sessionConfiguration:(NSURLSessionConfiguration *)configuration
{
    self = [super initWithSessionConfiguration:configuration];
    if (!self) {
        return nil;
    }

    // Ensure terminal slash for baseURL path, so that NSURL +URLWithString:relativeToURL: works as expected
    if ([[url path] length] > 0 && ![[url absoluteString] hasSuffix:@"/"]) {
        url = [url URLByAppendingPathComponent:@""];
    }

    self.baseURL = url;

    self.requestSerializer = [AFHTTPRequestSerializer serializer];
    self.responseSerializer = [AFJSONResponseSerializer serializer];

    return self;
}

#五、instancetype
Using instancetype instead of id in appropriate places improves type safety in your Objective-C code.  摘自苹果文档
这样写更安全,苹果官方文档也有举例,id返回的是任意类型,而instancetype返回的本类的对象,这样编译器能检测消息是否发错。

To make sure instancetype factory methods have the right subclassing behavior, be sure to use [self class] when allocating the class rather than referring directly to the class name. 
创建对象的时候尽量用[self class],而不是直接用类名。