0%

计算机最宝贵的资源就是CPU和内存,因此所谓的优化其实就是在”空间”和”时间”之间权衡。以空间换取更短的时间响应,表现在可能会增加额外的内存开销如:cell的重用、高度的缓存甚至布局的缓存等。

优化

1.cell的重用

注意重用可能导致的数据错乱问题。

参考:UITableViewCell重用导致的图片错乱问题

2.提前计算好cell的高度并且缓存起来

UITableView代理方法的执行顺序:
系统会先调用numberOfRowsInSection来获取cell的行数,然后再多次(和numberOfRow正相关)调用heightForRow来确定contentSize及cell的位置,最后才会调用cellForRow显示当前屏幕的cell.

由于heightForRow会频繁的调用,因此该方法里一定不要进行大量重复的计算.所以cell的高度需要进行缓存,然后在heightForRow方法中直接返回.可采用的策略:网络请求完成后就计算好每个cell的高度,并缓存到对应的model中.更有甚者会在此时连cell的子视图布局都计算好.

cell的高度计算与缓存时效问题?

3.避免阻塞主线程

阅读全文 »

1. 创建要公开的pod库

主要包含pod源码和pod sepc文件、许可证等。

这个过程可以先在本地创建好,再到GitHub创建对应的仓库,然后将本地pod添加到远程仓库。

也可以先在GitHub创建好仓库,再clone到本地,然后在clone的目录下创建pod。

pod sepc文件的说明可以参考:

CocoaPods 系列之三 Podspec 语法说明

cocoapods官网文档

Podspec Syntax Reference

创建sepc文件:

1
pod spec create 库名
阅读全文 »

1. 创建私有pod spec仓库

因为制作的是私有库所以就不能把pod sepc文件存放到cocoapods的公开仓库中了,因此需要在GitHub上新建一个repository XQSpecs用于保存所有的私有pod spec。

如果已经有自己的私有pod spec仓库,则这一步可跳过。

2. 创建私有pod库

主要包含pod源码和pod sepc文件、许可证等。

创建pod库,可以使用命令:pod lib create xxx,创建好模板pod,然后基于模板修改。也可以全部自己手动创建。

进入本地目的目录,使用命令:pod lib create xxx,然后基于模板修改。

3. 验证pod库

pod源码和pod sepc文件都准备好后,别着急发布,先验证pod库的可用性:

pod lib lint xxx.podspec或者使用:pod lib lint AlgorithmUtils.podspec --allow-warnings,忽略警告。

阅读全文 »

iOS中设置圆角大致有下面几种办法,每一种都有各自的优缺点,结合场景选择合适的方案才是最佳处理。

1.cornerRadius

1
2
Setting the radius to a value greater than 0.0 causes the layer to begin drawing rounded corners on its background. By default, the corner radius does not apply to the image in the layer’s contents property; it applies only to the background color and border of the layer. However, setting the masksToBounds property to YES causes the content to be clipped to the rounded corners.
The default value of this property is 0.0.

由于cornerRadius只对背景色和边框有效而对layer的contents并不起作用,因此一般都会配合masksToBounds使用。

苹果在iOS9后对cornerRadius+masksToBounds做了优化,当contentMode和backgroundColor为默认值时即:

1
2
imgView.contentMode = UIViewContentModeScaleToFill;
imgView.backgroundColor = [UIColor clearColor];

不会导致离屏渲染,否则还会离屏渲染,用View Debugging查看UIImageView会有黄色标识。

下面测试下cornerRadius+masksToBounds对FPS的影响。

在iPhone5s,10.3.3上运行一个一屏cell上有36个圆角的Demo,imgView的contentMode和backgroundColor都不使用默认值:

阅读全文 »

ROI

return on investment,投资回报率。

投资回报率的计算公式:

1
投资回报率 = (收益 - 成本)/ 成本 * 100%

eg:

项目A投入本金100,最后可以110,那么ROI = (110 - 100)/ 100 * 100% = 10%

项目B投入本金100,最后可以105,那么ROI = (105 - 100)/ 100 * 100% = 5%

通过计算应该选择项目A。

投资报酬率的优缺点

优点:

阅读全文 »

本文主要分析支付宝里的花呗,借呗,备用金背后的年化收益率。

在使用支付宝花呗的时候,还款页面除了正常还款外还有一些什么账单分期、最低还款、延期还款之类烂七八糟的东西:

似乎是在替用户着想,但真实情况是不是如此呢?下面将仔细分析一下花呗分期的真实年利率。

账单分期

花呗分期数与手续费率如下:

花呗
3期 2.50%
6期 4.50%
9期 6.50%
12期 8.80%

每期手续费 = 分期金额 / 分期期数 * 手续费率

每期还款数 = 分期金额 / 分期期数 + 每期手续费 = 每期手续费 * (1 + 手续费率 ) / 手续费率

总手续费 = 分期金额 * 手续费率

阅读全文 »

对于私有属性和方法,子类和父类同名基本上没有什么影响.但是有几点需要注意一下:

如果是属性同名,子类和父类会拥有各自独立的实例变量。

如果是方法同名,按照消息发送的过程,执行的自然是子类中的方法。

举个栗子:

父类:

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
33
34
35
36
37
38
39
40
41
42
43
44
@interface Animal : NSObject

@property (nonatomic, copy) NSString *name;
@property (nonatomic, assign) NSInteger age;

- (instancetype)initWithName:(NSString *)name age:(NSInteger)age;

- (void)hello;

@end

@interface Animal ()

@property (nonatomic, copy) NSString *hobbit;

@end

@implementation Animal

- (instancetype)initWithName:(NSString *)name age:(NSInteger)age {
self = [super init];
if (self) {
_name = name;
_age = age;
}
return self;
}

- (void)hello {
NSLog(@"父类方法,%@ %ld %@", _name, (long)_age, self.hobbit);
}

- (void)run {
NSLog(@"父类方法run");
}

- (NSString *)hobbit {
if (_hobbit == nil) {
_hobbit = @"unknown";
}
return _hobbit;
}

@end

子类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
@interface Person : Animal

@end

@interface Person ()

@property (nonatomic, copy) NSString *hobbit;

@end

@implementation Person

- (void)hello {
[super hello];

NSLog(@"子类方法,%@ %ld %@", self.name, (long)self.age, self.hobbit);

[self performSelector:@selector(run)];
}

@end

属性同名,拥有各自独立的实例变量:

阅读全文 »

Xcode11.3.1,Swift5环境.

在App开发中经常需要将服务端返回的JSON数据转化为模型使用,选择一个好的数据模型转换框架有助于提高开发体验以及减少转换过程中的错误.

我们希望框架支持纯Swift类,结构体,OC类,因此YYModel和MJExtension等一系列优秀的OC数据模型转换框架是不满足要求的,因为它们都需要模型继承自NSObject.

目前使用较多的数据模型转换框架有:

  1. 系统自带的基于Codable的JSONDecoder/JSONEncoder.
  2. HandyJSON
  3. ObjectMapper

下面简单介绍一下各框架的使用,并从框架的使用便捷性和数据容错性上进行一个比较.

JSONDecoder/JSONEncoder

介绍JSONDecoder之前,先来看下Codable是什么.

Codable是Swift 4.0开始引入的新特性.Codable定义:public typealias Codable = Decodable & Encodable,可以看到Codable是一个类型别名,代表同时遵守Decodable和Encodable协议.

Decodable协议定义了一个解码函数:

阅读全文 »

多态

多态指的是允许父类的指针指向子类的对象,当指针指向不同的子类对象时,给它发送同一个消息就会有不同的响应.

如下定义一个父类Animal和二个子类Dog,Cat.

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
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
@interface Animal : NSObject

- (void)run;

+ (void)bark;

+ (void)canClimb:(void(^)(BOOL can))blk;

@end

@implementation Animal

- (void)run
{
NSLog(@"%@ run", self);
}

+ (void)bark {
NSLog(@"%@ bark", self);
}

+ (void)canClimb:(void (^)(BOOL))blk {
!blk ?: blk(NO);
}

@end

...
@implementation Dog

- (void)run
{
NSLog(@"%@ run", self);
}

+ (void)bark {
NSLog(@"%@ bark", self);
}

+ (void)canClimb:(void (^)(BOOL))blk {
!blk ?: blk(NO);
}

@end

...

@implementation Cat

- (void)run
{
NSLog(@"%@ run", self);
}

+ (void)bark {
NSLog(@"%@ bark", self);
}

+ (void)canClimb:(void (^)(BOOL))blk {
!blk ?: blk(YES);
}

@end

接下来我们来个反射+多态:

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
NSArray *clsArr = @[@"Animal", @"Dog", @"Cat"];
for (NSString *clsStr in clsArr) {
Class cls = NSClassFromString(clsStr);
id obj = [cls new];
[obj run];
}

for (NSString *clsStr in clsArr) {
Class cls = NSClassFromString(clsStr);
[cls performSelector:@selector(bark)];
}

//手动写全
for (NSString *clsStr in clsArr) {
Class cls = NSClassFromString(clsStr);
[cls canClimb:^(BOOL can){
NSLog(@"%@ can climb:%d",cls, can);
}];
}

//使用performSelector
for (NSString *clsStr in clsArr) {
Class cls = NSClassFromString(clsStr);
[cls performSelector:@selector(canClimb:) withObject:^(BOOL can){
NSLog(@"%@ can climb:%d",cls, can);
}];
}

以上需要注意的是:

Xcode对于id类型调用实例方法,实例方法会有补全提示.对于Class类型调用类方法,类方法就没有补全提示,但你写全后也不会报错.

对于类方法的动态调用可以使用performSelector,也可以手动写全,这里Xcode不会自动补全不知道为什么.

主要步骤

  • 安装环境
  • 初始化项目
  • 部署
  • 配置站点信息
  • 配置主题信息

下面是具体的步骤:

安装环境

安装node.js

安装hexo

初始化项目

使用 Hexo 的命令行创建一个项目.

hexo init "name"

调用 Hexo 的 generate 命令,将 Hexo 编译生成 HTML 代码.

阅读全文 »