梦幻泡影

孔思哲的博客空间

0%

使用homebrew安装redis

1
$ brew install redis

终端输出

1
2
3
4
5
6
7
8
9
10
==> Downloading http://download.redis.io/releases/redis-3.2.3.tar.gz
######################################################################## 100.0%
==> make install PREFIX=/usr/local/Cellar/redis/3.2.3 CC=clang
==> Caveats
To have launchd start redis now and restart at login:
brew services start redis
Or, if you don't want/need a background service you can just run:
redis-server /usr/local/etc/redis.conf
==> Summary
🍺 /usr/local/Cellar/redis/3.2.3: 10 files, 1.7M, built in 21 seconds

从以上日志输出可以看出,如果需要给redis服务端指定配置文件,
启动命令应该是这样的:

1
$ redis-server /usr/local/etc/redis.conf
阅读全文 »

将图片转化裁剪为圆形的头像

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
-(UIImage*) imageToHeadView:(UIImage*)image withParam:(CGFloat)inset{

//先获取大小
CGFloat lengthW = CGImageGetWidth(image.CGImage);
CGFloat lengthH = CGImageGetHeight(image.CGImage);
CGFloat cutSzie;
//判断长宽比,获得最大正方形裁剪值
if(lengthW>= lengthH){
cutSzie = lengthH;
}
else cutSzie = lengthW;
//执行裁剪(为正方形)
CGImageRef sourceImageRef = [image CGImage]; //将UIImage转换成CGImageRef
CGRect rect = CGRectMake(lengthW/2-cutSzie/2, lengthH/2 - cutSzie/2, cutSzie, cutSzie); //构建裁剪区
CGImageRef newImageRef = CGImageCreateWithImageInRect(sourceImageRef, rect); //按照给定的矩形区域进行剪裁
UIImage *newImage = [UIImage imageWithCGImage:newImageRef]; //将CGImageRef转换成UIImage
//取圆形
UIGraphicsBeginImageContextWithOptions(newImage.size, NO, 0);
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetFillColorWithColor(context, [UIColor clearColor].CGColor);
CGContextFillPath(context);
CGContextSetLineWidth(context, .5);
CGContextSetStrokeColorWithColor(context, [UIColor clearColor].CGColor);
CGRect newrect = CGRectMake(inset, inset, newImage.size.width - inset * 2.0f, newImage.size.height - inset * 2.0f);
CGContextAddEllipseInRect(context, newrect);
CGContextClip(context);

[newImage drawInRect:newrect];
CGContextAddEllipseInRect(context, newrect);
CGContextStrokePath(context);
UIImage *circleImg = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return circleImg;
}

调用:

1
2
UIImage *img = [UIImage imageNamed:@"edit_background1.jpg"];
img = [self imageToHeadView:img withParam:0]; //封装的方法,从中间裁剪为圆形,后面参数为偏移量

作为JS的核心,回调函数和异步执行是紧密相关的,也是必须跨过去的一道个门槛。

那么究竟什么是回调函数(Callback),网上有许多的文章,这些文章大概分成两类,第一类术语太多,看不懂。另一类反过来,太过于生活化,讲的是一些脱离编程的例子,还是看的人晕头转向。
其实回调函数并不复杂,明白两个重点即可:

1. 函数可以作为一个参数在另一个函数中被调用

2. 大多数语言都是同步编程语言,比如现在我们有3行代码,那么系统一定是一行一行按顺序向下执行的,第一行执行完了,执行第二行,紧跟着最后执行第三行,你可能会说这不是废话吗?且慢,在JS里则不尽然,比如有3行代码,并不是排在最前面的代码就是最先执行完毕的,很有可能是最后一行语句最先执行完,然后排在最前面的那行反而是最后执行完毕的,所以我们说JS是异步编程语言。

下面以node.js为例,举一个例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
var fs = require("fs");
var c = 0

function f(x) {
console.log(x)
}

function writeFile() {
fs.writeFile('input.txt', '我是通过fs.writeFile 写入文件的内容', function (err) {
if (!err) {
c = 1
console.log("文件写入完毕!")
}
});
}

writeFile()
f(c)

以上代码不难理解,就是设置一个全局变量c = 0,然后执行writeFile函数(也就是写入一个文件input.txt),写完之后让c=1,然后再调用f()函数,f()函数简单至极,就是把打印一个变量,仅此而已。

按照正常逻辑,首先c=0,然后在调用writeFile函数的时候里面有一句c=1,我们先调用的writeFile,所以c=1肯定是会被执行到的,那么结果应该是打印1,但是万万想不到,结果是0,明明我们在writeFile函数里我们重新对c进行了赋值,为什么结果还是0呢?

因为程序运行到writeFile()这一行的时候,是一个比较耗时的IO操作,系统并不会卡在此处,死等writeFile执行完毕再执行下一条语句,而是直接下一条代码,即f(c),而此时c并没有被重新赋值为1,所以打印出来的结果还是0 ! 

这时候就需要搬出我们的主角“回调函数”了,改写一下writeFile函数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
var fs = require("fs");

function f(x) {
console.log(x)
}

function writeFile(callback) { //关键字callback,在这里就是指f()
fs.writeFile('input.txt', '我是通过fs.writeFile 写入文件的内容', function (err) {
if (!err) {
console.log("文件写入完毕!")
c = 1
callback(c) // 此行相当于f(c)
}
});
}
var c = 0
writeFile(f) // 函数f作为一个参数传进writeFile函数

我们在writeFile函数的形参里加入了一个关键字callback,表示这是一个回调函数,也就是前面所说的重点1,即所谓的“以函数为参数”,然后当文件写入完毕后,我们执行c=1, 然后再用一次callback关键字,在这里,关键字”callback”就是f()函数的化身,表示我们在此处调用一次f()函数.

如果你看明白上面的代码,那么我们现在开始用一句话攻略做一个总结:

【在大多数编程语言中,函数的形参总是由外往内向函数体传递参数,但在JS里如果形参是关键字”callback”则完全相反,它表示函数体在完成某种操作后由内向外调用某个外部函数】
所谓的“回调”,就是回头调用的意思。本例子中即是:让我先写文件,写操作结束后,我再回头调用f()函数。

有时候,我们会看到一些回调函数并没有使用callback关键字,这种连callback关键字和函数名都省略了,直接在函数的形参中嵌入一个function的写法,在js代码中更为常见,其本质上仍然是回调函数。

pod 组件验证时报错,Could not find a ios simulator, Ensure that Xcode -> Window -> Devices has at least on

执行 pod lib lint 时,报错:

ERROR | [iOS] unknown: Encountered an unknown error (Could not find a ios simulator (valid values: com.apple.coresimulator.simruntime.ios-10-3, com.apple.coresimulator.simruntime.ios-12-1, com.apple.coresimulator.simruntime.ios-8-1, com.apple.coresimulator.simruntime.tvos-12-1, com.apple.coresimulator.simruntime.watchos-5-1). Ensure that Xcode -> Window -> Devices has at least one ios simulator listed or otherwise add one.

 

解决办法:

1, 升级CocoaPods(使用的gem 源: https://gems.ruby-china.com/)

sudo gem install cocoapods

再次执行    pod spec lint –verbose –allow-warnings –use-libraries

验证通过

Cocoapods 遇到You don’t have write permissions for the /usr/bin directory.

安装cocoapods时候

命令 sudo gem install cocopods

提示

tiantaodeMacBook-Pro:~ tiantao$ sudo gem install cocoapods

ERROR: While executing gem … (Gem::FilePermissionError)

You don’t have write permissions for the /usr/bin directory.

解决方案 有人说 前面加sudo 明明已经加了 是无写入到/usr/bin directory 权限

执行此命令即可

sudo gem install cocoapods -n /usr/local/bin

iOS逆向工程 - fishhook原理

fishhook是Facebook提供的一个动态修改链接mach-O文件的工具。利用MachO文件加载原理,通过修改懒加载和非懒加载两个表的指针达到C函数HOOK的目的。

前提

在分析fishhook原理前,我们先来想两个问题:
1. Mach-O文件是被谁加载的?
 我们知道,在程序启动的时候 Mach-O 文件会被 DYLD (动态加载器)加载进内存。加载完 Mach-O 后,DYLD接着会去加载 Mach-O 所依赖的动态库。
2. 何为ASLR技术?
地址空间布局随机化。它会让 Mach-O 文件加载的时候是随机地址。有了这个技术,Mach-O 文件每次加载进内存的时候地址都是不一样的。主要是为了防止逆向技术。
Mach-O 文件里只有我们自己写的函数,系统的动态库的函数是不在 Mach-O 文件里的。也就是说每次启动从 Mach-O 文件到系统动态库函数的偏移地址都是变化的。

问题

一、那么我们如何在 Mach-O 文件里找到系统的函数地址呢?或者说 Mach-O 文件是如何链接外部函数的呢?

我们程序的底层都是汇编,汇编代码都是写死的内存地址。我们该怎么找呢?而且系统的动态库在内存里面的地址是不固定的,每次启动程序的时候地址都是随机的。
苹果为了能在 Mach-O 文件中访问外部函数,采用了一个技术,叫做PIC(位置代码独立)技术。
当你的应用程序想要调用 Mach-O 文件外部的函数的时候,或者说如果 Mach-O 内部需要调用系统的库函数时,Mach-O 文件会:

先在 Mach-O 文件的 _DATA 段中建立一个指针(8字节的数据,放的全是0),这个指针变量指向外部函数。
DYLD 会动态的进行绑定!将 Mach-O 中的 _DATA 段中的指针,指向外部函数。

所以说,C的底层也有动态的表现。C在内部函数的时候是静态的,在编译后,函数的内存地址就确定了。但是,外部的函数是不能确定的,也就是说C的底层也有动态的。fishhook 之所以能 hook C函数,是利用了 Mach-O 文件的 PIC 技术特点。也就造就了静态语言C也有动态的部分,通过 DYLD 进行动态绑定的时候做了手脚。

我们经常说符号,其实 _DATA 段中建立的指针就是符号。fishhook的原理其实就是,将指向系统方法(外部函数)的符号重新进行绑定指向内部的函数。这样就把系统方法与自己定义的方法进行了交换。这也就是为什么C的内部函数修改不了,自定义的函数修改不了,只能修改 Mach-O 外部的函数。

接下来我们以 NSLog 为例,看 fishhook 是如何通过修改懒加载和非懒加载两个表的指针达到C函数HOOK的目的。(NSLog 是在懒加载表里)
注:对于非懒加载符号表,DYLD会立刻马上去链接动态库
   对于懒加载符号表,DYLD会在执行代码的时候去动态的链接动态库

阅读全文 »

社交软件红包技术解密(四):微信红包系统是如何应对高并发的

本文来自微信团队工程师方乐明的技术分享,原文地址:infoq.cn/article/2017hongbao-weixin,感谢原作者的分享。 点此进入原文

一、引言

每年节假日,微信红包的收发数量都会暴涨,尤以除夕为最。如此大规模、高峰值的业务需要,背后需要怎样的技术支撑?百亿级别的红包规模,如何保证并发性能与资金安全?

本文将为读者介绍微信百亿级别红包背后的高并发设计实践,内容包括微信红包系统的技术难点、解决高并发问题通常使用的方案,以及微信红包系统的所采用高并发解决方案。

二、分享者

方乐明:现任微信支付应用产品系统负责人,主要从事微信红包、微信转账、微信群收款等支付应用产品的系统设计、可用性提升、高性能解决方案设计等,曾连续多年负责春节微信红包系统的性能优化与稳定性提升,取得良好的效果。

三、微信红包的两大业务特点

微信红包(尤其是发在微信群里的红包,即群红包),业务形态上很类似网上的普通商品“秒杀”活动。

阅读全文 »