2019年8月读书心得

距离上一次读书大约有2年了吧~那会儿花了一个月的时间读完了挺厚的两本《基督山伯爵》。阅读给人带来的最直接的好处是,可以让心静下来,遇事莫急,先过过脑,思考思考,在做决策。

由于种种原因吧。重新拾起阅读这个习惯选择的第一本书,是来自华为CEO任正非先生桌头的《美国陷阱》


本书以作者弗雷德里克·皮耶鲁齐的亲身经历为依据,描述了美国利用其强大的国力“强制”实时其“长臂管辖”能力以实现其自身目的。

从书中的描写,我们可以看出,作者是这场隐蔽的经济战争的牺牲品、替罪羊。在他入狱之后,先后被自己的公司(法国阿尔斯通)所出卖,被自己的国家所遗忘。公司里的高管,人人只管着自保,而作者的祖国——法国,在政治上也没有任何可以谈判的筹码,只能忍气吞声。最终,阿尔斯通的CEO柏克龙以公司为筹码换取自身平安,将法国的“明珠”产业——阿尔斯通的电力产业,卖给了美国通用电气公司。

他们是如何做到的呢?

美国政府自认为有权追诉任何一家公司,只要它用美元计价签订合同,或者仅仅通过设在美国的服务器(如谷歌邮箱或微软邮箱)收发、存储(甚至只是过境)邮件,这些都被视为国际贸易工具。这就是美国人的一个把戏,他们把一项可能削弱自身企业的法律转变为干涉他国企业、发动经济战的神奇工具。
而到手的“罪犯”不需要是真正的幕后主使,只要美国政府愿意,那他就是。只要能达到他们的狼子野心,就可以了。

看完这本书,我又去查阅了“孟晚舟事件”,结果和我想的一样,这是美国故技重施的阴谋,想要通过相同的手法,对在通信领域有着举足轻重地位的中国公司“华为”入手。
略有不同的是,我们国家对此事高度关注,华为公司也在积极应对。

说到这里,忍不住想提一下中美的贸易战。作为一名普通老百姓,可能对贸易战的直观感受就是…没啥感觉,成天看新闻说贸易战,然后各种东西的涨价不知道和贸易战是否有关。不管我们相不相信,愿不愿意,这场经济战争,都已经打响了。我觉得我所能做的,就是相信我们的国家,能够在这场战斗中展现出我们的优势和强大国力。这里有一篇
《2019年8月中美贸易战简况总结》,个人觉得还是非常值得一读的。我们承认美国拥有世界上首屈一指的国力,但是如今的中国在世界上,也是有着举足轻重的力量。

最后提一下。

《美国陷阱》这本书的前29节,我看的是实体书。我并没有购买这本书。而是在支付宝的“浙江图书馆”借阅了这本书。并且它支持邮寄(邮政+京东),到手速度非常快。
而后面的章节,由于出差没有带书。在某读书软件中读完了剩余的内容。感觉电子书阅读,其实也是蛮能接受的,方便随时阅读,就是看久了屏幕,眼睛有点吃力。

iOS源码阅读——YYWebImage

加载网络图片是项目中比较常见的需求,YYWebImage是Github中比较好用的图片加载开源框架之一。YYWebImage是作者为UIImageView创建的Category,使得UIImageView的实例能够直接调用一个实例方法,就能获取网络图片的功能。

UIImageView+YYWebImage的实例方法

UIImageView+YYWebImage列举了5中方法供开发者使用,分别是:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
①- (void)yy_setImageWithURL:(nullable NSURL *)imageURL placeholder:(nullable UIImage *)placeholder;
②- (void)yy_setImageWithURL:(nullable NSURL *)imageURL options:(YYWebImageOptions)options;
③- (void)yy_setImageWithURL:(nullable NSURL *)imageURL
placeholder:(nullable UIImage *)placeholder
options:(YYWebImageOptions)options
completion:(nullable YYWebImageCompletionBlock)completion;
④- (void)yy_setImageWithURL:(nullable NSURL *)imageURL
placeholder:(nullable UIImage *)placeholder
options:(YYWebImageOptions)options
progress:(nullable YYWebImageProgressBlock)progress
transform:(nullable YYWebImageTransformBlock)transform
completion:(nullable YYWebImageCompletionBlock)completion;

⑤- (void)yy_setHighlightedImageWithURL:(NSURL *)imageURL
placeholder:(UIImage *)placeholder
options:(YYWebImageOptions)options
manager:(YYWebImageManager *)manager
progress:(YYWebImageProgressBlock)progress
transform:(YYWebImageTransformBlock)transform
completion:(YYWebImageCompletionBlock)completion;

从方法的具体实现中可以看到,①~④的方法实现,都是调用了方法⑤,只是参数传递有所不同。所以我们只需要着重阅读方法⑤的代码实现

具体实现——UIImageView+YYWebImage.m

  1. 判断传入的图片链接如果是NSString类型的实例,要先转换为NSURL类型的实例

  2. 三目运算,判断YYWebImageManager实例初始化与否,确保初始化完成

  3. _YYWebImageSetter

    1. 关于_YYWebImageSetter,作者的注解是:Private class used by web image categories.Typically, you should not use this class directly.它是Web图像类别使用的私有类。通常,您不应直接使用此类。
    2. 包含2个只读属性、和4个方法
      1. 属性:(NSURL*)imageURL、(int32_t) sentinel
      2. 方法:
        1. -(int32_t)setOperationWithSentinel: url: options: manager: progress: transform: completion:
        2. -(int32_t)cancel
        3. -(int32_t)cancelWithNewURL:
        4. +(dispatch_queue_t)setterQueue
      3. objc_getAssociatedObject:通过runtime获取UIImageView的动态属性setter,类型为_YYWebImageSetter
      4. 如果获取到的setter为空,则需要新建一个_YYWebImageSetter实例,并动态关联这个属性。
      5. [setter cancelWithNewURL:imageURL]通过新的图片链接,取消原来的线程操作。实现步骤:
        1. dispatch_semaphore_wait(_lock, DISPATCH_TIME_FOREVER)如果_lock的信号量值为0,则线程阻塞,不往下执行。否则,信号量-1(初始信号量为1),继续往下执行。
        2. 判断 _operation线程是否存在,如果存在,取消这个线程,并置空。
        3. 为 _imageURL变量赋值——新的图片连接
        4. sentinel = OSAtomicIncrement32(&_sentinel);值自增
        5. dispatch_semaphore_signal(_lock) 信号量+1
  4. _yy_dispatch_sync_on_main_queue确保在主线程执行后面的代码。

    1. 从内存缓存YYImageCacheTypeMemory中获取图片,如果获取成功,则执行complete(),结束操作。
    2. 未在内存缓存中获取到图片,继续执行。
      1. 通过 [_YYWebImageSetter setterQueue],获取到一个与全局队列优先级相同的队列,并异步执行后面的代码
      2. 预先创建和实现的 YYWebImageCompletionBlock _completion block。
      3. 实现 _YYWebImageSetter *setter的实例方法—— [setter setOperationWithSentinel:sentinel url:imageURL options:options manager:manager progress:_progress transform:transform completion:_completion]。
      4. 通过一路追随 _completion block的传递,发现进入了 YYWebImageOperation 类。
      5. YYWebImageOperation继承于 NSOperation。作者重写了NSOpration类的start,方法。并在恰当时机调用了自定义方法 _startOperation。
      6. _startOperation方法的实现
        1. 当_cache存在且用户没有设置 YYWebImageOptionUseNSURLCache 和 YYWebImageOptionRefreshImageCache 选项。会先去取图片缓存。
        2. 获取内存图片缓存,调用方法 [_cache getImageForKey:_cacheKey withType:YYImageCacheTypeMemory];。通过_cacheKey获取内存缓存。如果获取成功,结束后台线程;获取失败,则向下执行
        3. 当用户没有设置忽略磁盘缓存 YYWebImageOptionIgnoreDiskCache,则接下去,从磁盘获取图片缓存。
        4. 获取磁盘图片缓存,调用方法 [self.cache getImageForKey:self.cacheKey withType:YYImageCacheTypeDisk]。
          1. 如果从磁盘获取图片缓存成功,先将图片缓存到内存,并调用 _didReceiveImageFromDiskCache方法。
          2. 如果同磁盘获取图片缓存失败,则需要从网络请求图片数据。
        5. 通过网络请求获取图片。
          1. 通过 incrementNetworkActivityCount为请求数量+1
          2. 通过 connection: didReceiveData: 方法的回调,不断地获取数据。
          3. 在 connectionDidFinishLoading 的方法回调中,调用 _didReceiveImageFromWeb 方法。
          4. 通过 decrementNetworkActivityCount 为请求数量-1
          1. _didReceiveImageFromWeb成功从网络获取图片。将图片分别存入内存和磁盘缓存中。
        6. 回到之前实现的 _completion代码块。主要是一些动画特效。
  5. 通过completion:(nullable YYWebImageCompletionBlock)completion,将结果返回给开发者

总结

YYWebImage的实现合乎我们的直觉:

  • 查看缓存(1.内存;2.磁盘)
    • 缓存命中
      • 返回图片
      • 更新视图
    • 缓存未命中
      • 异步下载图片
      • 加入缓存
      • 更新视图

心得

之前尝试阅读过YYWebImage框架,当时的方法是一个类一个类看,从.h的属性、方法,到.m的具体实现。说实话,看起来着实有点烧脑和低效。读了Draven的《iOS 源代码分析 — SDWebImage》,有所启发,直接以API作为入口阅读源码,更具方向性,才会更有收获。
文章中涉及到了dispatch_semaphore队列优先级的知识。

iOS UITableView 长按移动Cell的位置

实现思路:

  1. 长按获取当前手指所在位置的indexPath
  2. 通过indexPath获取对应cell,并生成快照
  3. 移动。
    3.1. 快照跟随手指移动
    3.2. 当手指移动到其他cell的位置时,执行位置互换,和数据互换
  4. 放开手指,移除快照

实现步骤:

准备:(UITableView*)tableView,数据源(NSMutableArray*)lists

第一步:为tableView添加长按手势
1
2
3
UILongPressGestureRecognizer* longRec = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(longPress:)];
[_tableView addGestureRecognizer:longRec];

第二步:实现手势对应的操作。

UIGestureRecognizerStateBegan 时,选中cell。
通过手势在tableView的location,可以获取到tableView上对应的IndexPath,从而也能获取到对应的cell。

1
2
3
4
5
6
7
8
//UIGestureRecognizer 的实例方法,可获取手势在载体上的点坐标
- (CGPoint)locationInView:(nullable UIView*)view;

//UITableView 的实例方法,可获取屏幕上某个点下存在的indexPath
- (nullable NSIndexPath *)indexPathForRowAtPoint:(CGPoint)point;

//UIView 的实例方法,可生成屏幕快照,要求iOS 7.0+
- (nullable UIView *)snapshotViewAfterScreenUpdates:(BOOL)afterUpdates;

UIGestureRecognizerStateChanged 时,移动cell。
通过手势在移动中,不断的回调,获取相应的位置,当手势移动到其他cell的位置时,就可以进行数据和视图的对调。

1
2
3
4
5
6
7
8
9
//NSMutableArray 的实例方法,可快速交换数组中两个对象的位置
- (void)exchangeObjectAtIndex:(NSUInteger)idx1 withObjectAtIndex:(NSUInteger)idx2;

//UITableView 的实例方法,可快速交换两个cell的位置,带动画
- (void)moveRowAtIndexPath:(NSIndexPath *)indexPath toIndexPath:(NSIndexPath *)newIndexPath;

//UITableView 的实例方法,可快速交换两个section的位置,带动画
- (void)moveSection:(NSInteger)section toSection:(NSInteger)newSection;

UIGestureRecognizerStateEnded 时:放下cell,移除快照


完整的longPress:方法

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
- (void)longPress:(UILongPressGestureRecognizer*)sender{
UIGestureRecognizerState state = sender.state;
CGPoint location = [sender locationInView:_tableView];
switch (state) {
case UIGestureRecognizerStateBegan:{
NSLog(@"选中cell");
_selectIndexPath = [_tableView indexPathForRowAtPoint:location];
if (!_selectIndexPath) return;
UITableViewCell* cell = [_tableView cellForRowAtIndexPath:_selectIndexPath];
_snapShot = [self snapshotViewAfterScreenUpdates:cell];
_snapShot.frame = CGRectMake(0, location.y, _snapShot.bounds.size.width, _snapShot.bounds.size.height);
[self.view addSubview:_snapShot];
cell.contentView.hidden = YES;
}
break;
case UIGestureRecognizerStateChanged:{
NSLog(@"移动cell");
_snapShot.frame = CGRectMake(0, location.y, _snapShot.bounds.size.width, _snapShot.bounds.size.height);
NSIndexPath* changeIndexPath = [_tableView indexPathForRowAtPoint:location];
if (!_selectIndexPath || !changeIndexPath) return;
if (_selectIndexPath != changeIndexPath) {
NSLog(@"交换");
[self.lists exchangeObjectAtIndex:_selectIndexPath.row withObjectAtIndex:changeIndexPath.row];
//移动Section —— [self.tableView moveSection:0 toSection:0];
//移动row
[self.tableView moveRowAtIndexPath:_selectIndexPath toIndexPath:changeIndexPath];
UITableViewCell* selectCell = [_tableView cellForRowAtIndexPath:_selectIndexPath];
UITableViewCell* changeCell = [_tableView cellForRowAtIndexPath:changeIndexPath];
selectCell.contentView.hidden = NO;
changeCell.contentView.hidden = YES;
_selectIndexPath = changeIndexPath;
}
}
break;
case UIGestureRecognizerStateEnded:{
NSLog(@"放下cell");
[_snapShot removeFromSuperview];
_snapShot = nil;
if (!_selectIndexPath) return;
UITableViewCell* cell = [_tableView cellForRowAtIndexPath:_selectIndexPath];
cell.contentView.hidden = NO;
_selectIndexPath = nil;
}
break;
default:
break;
}
}

Demo

自定义UITableView左滑删除样式

最近在做番茄钟的项目,其中涉及到任务列表的界面,希望实现左滑删除的功能。UITableViewDelegate自带简单的左滑删除的接口,通过实现canEditRowAtIndexPath方法打开tableView可编辑的开关,再实现editActionsForRowAtIndexPath方法处理事件,UITableViewRowAction的实例允许修改文字和背景色。

而我的需求是想把删除键做成一个垃圾桶图标。而系统没有直接可用的API,那就只能曲线救国了。

首先,这个删除按钮在 iOS11 和 iOS11以下的系统中,所处的父级是不一样的。

在iOS11以前

删除按钮的父级是cell图。

iOS11+

删除按钮的父级类名为UISwipeActionPullViewUISwipeActionPullView的父级为UITableViewRowAction,也就是说UISwipeActionPullView和cell是同级的。

所以,两者需要以不同的方式实现。

在两种系统中,当还未左滑调出删除按钮时,输出cell或tableView的所有子视图,发现并没有删除按钮的存在。也就是说,他们是在需要的时候,被创建出来的。所以,我们需要重写某个方法去截获这个删除按钮。

在iOS11以前

重写insertSubview:atIndex方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
- (void)insertSubview:(UIView *)view atIndex:(NSInteger)index {
[super insertSubview:view atIndex:index];
DLog(@"insertSubview");
if ([view isKindOfClass:NSClassFromString(@"UITableViewCellDeleteConfirmationView")]) {
for (UIButton *btn in view.subviews) {

if ([btn isKindOfClass:[UIButton class]]) {
[btn setBackgroundColor:[UIColor clearColor]];
[btn mas_updateConstraints:^(MASConstraintMaker *make) {
make.width.mas_equalTo(adaptWidth(35));
make.height.mas_equalTo(adaptWidth(35));
make.centerX.mas_equalTo(0);
make.centerY.mas_equalTo(0);
}];

[btn setTitle:nil forState:UIControlStateNormal];
UIImage *img = [IMAGE(@"list_deleting") imageForThemeColor:[UIColor redColor]];
[btn setImage:img forState:UIControlStateNormal];
[btn setImage:img forState:UIControlStateHighlighted];
}
}
}
}

iOS11+

新建并使用一个继承于UITableView的控件,重写layoutSubviews方法。

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
- (void)layoutSubviews{
[super layoutSubviews];

//iOS11版本以上,自定义删除按钮:
if ([[[UIDevice currentDevice] systemVersion] doubleValue] >= 11.0) {
for (UIView *subview in self.subviews)
{
if([subview isKindOfClass:NSClassFromString(@"UISwipeActionPullView")])
{
UIView *swipeActionPullView = subview;
swipeActionPullView.backgroundColor = [UIColor clearColor];

UIButton *swipeActionStandardBtn = subview.subviews[0];
if ([swipeActionStandardBtn isKindOfClass:NSClassFromString(@"UISwipeActionStandardButton")]) {

[swipeActionStandardBtn mas_updateConstraints:^(MASConstraintMaker *make) {
make.width.mas_equalTo(adaptWidth(35));
make.height.mas_equalTo(adaptWidth(35));
make.left.mas_equalTo(0);
make.centerY.mas_equalTo(0);
}];
[swipeActionStandardBtn setTitle:nil forState:UIControlStateNormal];
[swipeActionStandardBtn setImage:[IMAGE(@"list_deleting") imageForThemeColor:[UIColor redColor]] forState:UIControlStateNormal];
}
}
}
}
}

*在iOS11以前,左滑cell不会走layoutSubviews的方法。在iOS11上,左滑时tableView不会走insertSubview:atIndex方法。

Diary

2018年9月5日 周三


今天尝试着将小程序上传提交审核了。
从8月8日创建项目开始,历时将近一个月时间,算是做了点东西出来。
一个产品在设计伊始应该先有个原型,但是我不是产品经理,所以我就用Page画了一些简单的图形,来提现界面的雏形。
然后…然后就直接上手开发了。
可发过程中也遇到了很多问题,例如如何获取小程序的全局变量,如何去适配屏幕的高宽,单位的使用,是用px,还是rpx,等等,等等
不过好在,所有这些问题,在搜索引擎的帮助下基本都能解决。
对JS的感觉是,既陌生又熟悉,因为同时在学习Swift的缘故,发现二者还是有一些相似之处。
HTML和CSS是上大学那会儿学的,写的时候,还是不得不时不时查阅文档才能达到想要的效果。
最近,腾讯还上线了云开发,但是目前还在公测阶段,需要申请公测资格,我填写了好几次信息,都没有收到允许公测的邮件..
所有后面直接用了Bomb的后台云。
Bomb后端云的免费版每月有10万次的API调用额度,20GB的存储空间,20GB的流量,以及30条短信。
如果用完了或者不够用,也可以按需充值。还是蛮方便的
这个小项目下做来,有些感慨,在做事情之前,还是应该有相对充分的准备。
对于不熟悉的语言,按需学习做项目的方式,会让人特别难受,特别是前期,还处于摸索的阶段,基本上是五行代码一小查,十行代码一大查的状态。
小程序的页面花了大概三周的时间,每天基本只用半天的时间去写(下午学习Swift),9个页面,包括信息的展示页面,和信息的发布界面,以及个人中心页面,最后只用来两个信息展示页面…内容的展示姑且先用CVS记录,再导入数据库进行管理。是骡子是马,先拉出去溜溜看吧。
估计在小程序上线过程中,还会遇到一些问题,不知道会不会因为功能过于简单,直接不让上了…

2018年9月2日 周一


使用Bomb作为小程序的后端,在线编辑数据库,亦可导入cvs的文件,非常方便使用。
不需要自己写后端代码,甚至连服务器都不需要部署跟购买,在满足需求的程度上够用了。


2018年2月11日 周日


添加了Livere评论控件,从此以后文章可以被评论了:)


2018年2月9日 周五


发现博客首页的_content内容摘要部分部分,无法点击进入文章详情。今天就在archer主题的文件里做了个小改动,实现内容的点击事件
实现方法也非常简单。首先需要找到首页的布局文件,其文件目录大概是:

1
/blogRootDir/themes/archer/layout/index.ejs

使用文档编辑器打开index.ejs文件,找到以下内容:

1
2
3
<div class="abstract-content">
<%- _content %>
</div>

改成如下代码,就搞定了:

1
2
3
4
5
<a class="abstract-title" href = "<%- url_for(_post.path) %>" >
<div class="abstract-content">
<%- _content %>
</div>
</a>

2018年2月8日 周四


今天写下第一篇,和技术有一点点关系的博客。虽然大部分内容是通过粘贴和借鉴的。不过在排版和Markdown的语法上,还是得到了学习。
想对自己说,再接再厉吧。
以后想通过Diary这个页面,记录自己生活和学习的点滴,希望在未来的某一天,能看到自己逐步地成长。

使用Xcode的Instruments(Leaks)监测App的内存泄漏问题

最近项目提交App Store审核,有些闲暇时间,打算用Instruments工具里的Leaks
检查一下项目中存在的内存泄漏问题。

一、准备工作

1.edit scheme

修改为测试环境

将Profile中的Build Configuration选为Debug

2.Debug Information Format

设置调试运行的时候生成 dSYM文件(用于代码定位)

Build Settings --> Debug Information Format

二、开始监测

1.打开Instruments

在Xcode的导航栏中找到Instruments。

Xcode --> Open Developer Tool --> Instruments

2.双击选择Leaks

3.选择设备和项目

找到运行的设备和正在运行的项目。

选好设备和项目,点击左侧的大红点,项目会在对应的设备中重新运行一次。并做好监测准备

4.内存监测

由于Leaks是动态监测,所以需要一边手动操作App,一边观察Leaks界面上的变化。当出现红色叉叉时,说明出现了内存泄漏,可以暂停进程,进行查看

5.定位内存泄漏的位置
选择 Leaks ——> Call Tree,最底下会出现4个选框

5.1 点击第二个Call Tree,勾选 Invert Call TreeHide System Libraries

勾选前
![](https://gitee.com/hongdongjie/gg266picgo/raw/master/pic4blog/监测App的内存泄漏/7.call tree不选之前的对比图.png)

勾选后
![](https://gitee.com/hongdongjie/gg266picgo/raw/master/pic4blog/监测App的内存泄漏/7.call tree 选项.png)

6.确认位置,修改代码

此时显示的就是若干条内存泄漏的代码部分,选择其中一条双击,即可显示代码。还可直接跳转到代码在Xcode中额具体位置

多线程的理解——队列与执行方式

多线程的理解——队列与执行方式

1.队列类型

  • 串行队列:顺序执行,一次执行一个任务。依次从队列中取出一个任务执行,必须一个任务执行完了,才能从队列里面取出下一个任务。
  • 并行队列:任务是按照加入到队列中的顺序开始执行,但任务完成时的顺序是不确定的。
  • 主队列:主线程中的串行队列(系统默认创建)。
  • 全局队列:是全局的并行队列(系统默认创建。几乎等效于并行队列)。

2.执行方式

  • 同步执行sync:不开新线程
  • 异步执行async:开辟新线程

3.队列与执行方式

  • 串行队列同步执行:不开线程,在原来线程里面一个一个顺序执行
  • 串行队列异步执行:开一条线程,在这个新线程里面一个一个顺序执行
  • 并行队列同步执行:不开线程,在原来线程里面执行
  • 并行队列异步执行:开多个线程,并发执行(不一定是一个一个)执行

4.死锁问题

死锁问题的理解,可参考:《为什么dispatch_sync在主线程会死锁》

Mac上搭建基于GitHub的Hexo博客

2017农历的最后几天,项目都完成得差不多了。想着建立一个自己的博客,花了两天时间,在网上搜索各种资料,总算是把个人博客建起来了。过程就是不断试错,是在进行不下去了,就推翻重来。本人是一枚iOS coder,工作机是一台Mac,所以就讲讲在macOS系统上如何基于Hexo+Github创建个人博客。文章开始前,需要提醒一下,文中出现的$符号,在终端中都是不需要输入或粘贴的。

环境配置

Node.js

用来生成静态页面。可直接在Node.js官网,下载镜像安装。

Git

用来提交本地的Hexo内容到Github上。
电脑上如果已经装了Xcode,可不比进行本步骤,因为Xcode自带git。
如果没有Xcode,可以使用 Homebrew, MacPorts :brew install git;或下载 安装程序 安装
如果不是iOS开发者,其实真的没必要为了建站下一个好几G的Xcode

安装Hexo

所有必备的应用程序安装完成后,即可使用 npm 安装 Hexo。

1
$ npm install -g hexo-cli

这里如果报错,可以尝试sudo命令。输入管理员密码(Mac登录密码)即开始安装。

1
$ sudo npm install -g hexo-cli

初始化

终端cd到一个你选定的目录(Mac支持直接将文件或文件夹拖入终端,直接显示路径),然后执行hexo init命令

1
$ hexo init blogName

这里需要提一下,如果需要把博客的根目录文件夹建在桌面上:cd到桌面,然后执行hexo init blogName命令即可。系统会创建blogName这个目录在桌面上。
下一步,cd到blogName,执行安装命令

1
$ npm install

安装完毕后,指定文件夹的目录如下

1
2
3
4
5
6
7
8
.
├── _config.yml
├── package.json
├── scaffolds
├── source
| ├── _drafts
| └── _posts
└── themes

此时,可开启hexo服务器

1
2
3
$ hexo server
简写:
$ hexo s

服务器成功开启。系统会提示

1
2
INFO  Start processing
INFO Hexo is running at http://localhost:4000/. Press Ctrl+C to stop.

此时,在可以在浏览器中输入http://localhost:4000/127.0.0.1:4000 ,如果出现了下图页面,就说明已获得“阶段性”的成功。
img

关联Github

新建仓库

在自己的GitHub账户上创建一个新的仓库(repository)
命名规则为:你的用户名.github.io,如a334713698.github.io

配置文件

在blogName文件中,找到名为_config.yml的文件,使用任意文本编辑器打开此文件。
找到如下代码:

1
2
3
4
# Deployment
## Docs: https://hexo.io/docs/deployment.html
deploy:
type:

可通过键盘command+F,调起编辑器的搜索功能,查找“deploy”字段
并将内容填充为:

1
2
3
deploy:
type: git
repository: https://github.com/a334713698/a334713698.github.io.git

注意:repository:后填写的应该是自己的创建的仓库地址。

生成静态页面

此时应保证自己在blogName根目录下。如果不在指定目录,在终端上输入cd ,再直接将指定文件夹拖进终端,即可获取文件夹路径,按下回车,进入指定目录下。
接着执行generate命令:

1
2
3
$ hexo generate
简写:
$ hexo g
1
2
3
4
5
6
7
8
若出现如下报错:
ERROR Local hexo not found in ~/blog
ERROR Try runing: 'npm install hexo --save'

则执行命令:
$ npm install hexo --save

若无报错,自行忽略此步骤。

部署网页到git上

执行部署的命令

1
2
3
$ hexo deploy
简写:
$ hexo d
1
2
3
4
5
6
7
8
9
10
11
12
若执行命令hexo deploy仍然报错:
无法连接git或找不到git

则执行命令:
$ npm install hexo-deployer-git --save

然后再次执行
$ hexo generate //生成静态页面
$ hexo deploy //部署到git

tip:静态页面生成和部署两个步骤可以合并写成:
$ hexo g -d

若未关联过Github,则执行hexo deploy命令时终端会提示你输入Github的用户名和密码,正确填写GitHub的账号密码即可。
hexo deploy部署成功后,浏览器中打开网址 http://a334713698.github.io (将a334713698换成自己的用户名)也能看到博客的主页。

添加ssh key到Github

检查SSH keys是否存在Github

执行如下命令,检查SSH keys是否存在。

1
$ ls -al ~/.ssh

如果有文件id_rsa.pubid_dsa.pub,则直接进入将SSH key添加到Github中的步骤,否则进入下一步生成SSH key。

生成新的ssh key

执行如下命令生成public/private rsa key pair,注意将your_email@example.com换成你自己注册Github的邮箱地址。

1
$ ssh-keygen -t rsa -C "your_email@example.com"

默认会在相应路径下(~/.ssh/id_rsa.pub)生成id_rsa和id_rsa.pub两个文件。

将ssh key添加到Github中

Finder(访达)前往~/.ssh/id_rsa.pub打开id_rsa.pub文件,里面的信息即为SSH key,将这些信息复制到Github的Add SSH key页面即可。

1
进入Github –> Settings –> SSH and GPG keys –> add SSH key

Title任意填(也可不填,我就没填),粘贴内容要从头部的ssh-rsa开始粘,将复制的内容粘贴到Key里,点击下方Add key完成设置。

结尾

到这里,建站工作基本搞定。接下去,就可以发布文章,更换主题了。
本文大部分内容都参考于与佳期的个人博客《Mac上搭建基于GitHub的Hexo博客
述》
一文。文中还涉及文章发布,域名绑定,主题更换等内容,都非常有帮助。

第一篇文章

捯饬了两天,终于把博客弄起来了,随便写点儿什么吧..
通过看Hexo官网的文档,初步了解了Hexo建站的方式和一些常用的命令行
另外参考了两名博主的文章,对本次建站都非常地有帮助,分别是:嘟嘟独立博客与佳期的个人博客
使用的theme来自Yilia (hexo-theme-yilia)可直接点击括号里的链接,前往主题所存的Github页面

2018年2月8日
更换主题:来自Wee(hexo-theme-archer)

创建博客的初衷:

  • 博客的存在,能够表达自己的情感;
  • 书写技术文章,督促自己对技术知识点的归纳、总结和理解;
  • 自主建站,非常酷。这也是当初选择编程这项实业的原因。

请我喝杯咖啡吧~

支付宝
微信