iOS开发即时通讯之Openfire+Spark配置

Spark 提供了客户端一个基本的实现,并提出了一个很好的插件架构,也是建议基于插件方式来实现你新增加的功能,而不是去改它的源代码,这样有利于项目架构,把原始项目的影响降到最低。

Openfire 是基于XMPP 协议的IM 的服务器端的一个实现,虽然当两个用户连接后,可以通过点对点的方式来发送消息,但是用户还是需要连接到服务器来获取一些连接信息和通信信息的,所以服务器端是必须要实现的。Openfire 只提供了一些基本功能,但它提供插件的扩展,像Spark 一样,建议使用插件扩展的方式来增加新的功能,而不是修改源代码。

下面展示一下如何搭建Openfire+Spark环境的过程。

先到官网下载openfire+spark

下载地址:http://www.igniterealtime.org/downloads/index.jsp

选择Mac版的dmg文件下载。

安装前需先下载安装需要的jdk文件和MySql和Mysql-workbench.

jdk下载链接: http://pan.baidu.com/s/1dDLHFdZ 密码:xe9u

Mysql下载链接:http://pan.baidu.com/s/1o74KthK 密码:asib

Mysql_workbench下载链接:http://pan.baidu.com/s/1geeA1aV 密码:dmyp

分别点击安装。使用MySqlWorkbench创建openfire数据库

打开MySqlWorkbench

点击New Connection新建一个连接

Connection Name可随便写 其他使用默认设置即可

然后双击建立的连接

点击红色标记处

Schema Name处填写openfire,然后点击右下角Apply, 则创建好了openfire数据库。

安装好MySql和Opnefire好之后,会在系统偏好设置中显示

分别点击启动连接

Openfire在点击start openfire时老是启动失败,后来网上找了下,解决方法如下

打开终端,输入如下命令

1
sudo chmod -R 777 /usr/local/openfire/bi

1
sudo su
1
cd /usr/local/openfire/bin
1
export JAVA_HOME=`/usr/libexec/java_home`
1
echo $JAVA_HOME /Library/Java/JavaVirtualMachines/jdk1.8.0_51.jdk/Contents/Home
1
cd /usr/local/openfire/bin
1
./openfire.sh

不过每次电脑重新启动还是打开不了,只能再次输入上面命令。

如果Openfire需要卸载使用如下命令

1
sudo rm -rf /Library/PreferencePanes/Openfire.prefPane
1
sudo rm -rf /usr/local/openfire
1
sudo rm /Library/LaunchDaemons/org.jivesoftware.openfire.plist

接下来配置Opnefire服务器

系统偏好设置中,Opnefire启动后,点击Open Admin Console,会自动在本地浏览器打开web配置页。

按如下过程配置

数据库驱动选择:MySQL 上文已提到需提前安装好Mysql和创建好数据库

JDBC驱动,默认不变 com.mysql.jdbc.Driver

数据库URL:这里设置为jdbc:mysql://localhost:3306/openfire,前提是已经存在openfire数据库,上文已展示创建过程。否则会报如下错误:The Openfire database schema does not appear to be installed. Follow the installation guide to fix this error.

在配置openfire和创建数据库的过程中可能会出现其他问题,可能没有权限或者版本过低等,自行百度吧,这个问题不一不好汇总。

spark的安装比较容易,一路next就可以。

注册账号登陆后可以添加好友发送信息等。

这时候在打开系统偏好设置,打开openfire,点击open admin console

在后台就可以看到相关账户信息了。

配置过程中建议到官网下载,使用最新版本,否则可能配置不成功!


如有任何疑问或问题请联系我:fishnewsdream@gmail.com,欢迎交流,共同提高!

Objective-C/Swift技术开发交流群201556264,讨论何种技术并不受限,欢迎各位大牛百家争鸣!

微信公众号OldDriverWeekly,欢迎关注并提出宝贵意见

老司机iOS周报,欢迎关注或订阅

刚刚在线工作室,欢迎关注或提出建设性意见!

刚刚在线论坛, 欢迎踊跃提问或解答!

如有转载,请注明出处,谢谢!

Hexo博客yilia主题设置

Hexo博客搭建完成后,页面长这样

简单大气,然而很多人觉得这不够精炼,想自己定制更个性化的主题。有哪些好看的Hexo主题呢,这是知乎上的问题,答的很全面,读者可以点进去看下,其中列举了github上starts比较多的前十五名的主题样式,当然还有更多。我选择的主题是

链接地址: https://github.com/ChinaFishNews/hexo-theme-yilia.git

这个主题也是我在尝试了几个主题之后最终选择的一个,最终效果如下

如何设置

1.打开Hexo所在的目录

这样在themes目录下就下载了yilia主题

2.修改Hexo目录下的_config,yml文件: theme:yilla

3.前往themes文件,打开yilia文件夹,打开_config.yml文件作如下设置

其中的一些设置可随意设定,并不固定,这样基本设置就已完成,里面包含使用的多说评论系统。

设置完成后,可能还需要添加统计功能,统计访问量、单篇文章访问量等,这个需要修改里面的JS代码。这个忘了记录具体修改的文件,就不贴出来了,大家可自行百度设置方法,效果如下

然后使用如下命令发布即可。

1
hexo generate
1
hexo deploy

如有任何疑问或问题请联系我:fishnewsdream@gmail.com,欢迎交流,共同提高!

Objective-C/Swift技术开发交流群201556264,讨论何种技术并不受限,欢迎各位大牛百家争鸣!

微信公众号OldDriverWeekly,欢迎关注并提出宝贵意见

老司机iOS周报,欢迎关注或订阅

刚刚在线工作室,欢迎关注或提出建设性意见!

刚刚在线论坛, 欢迎踊跃提问或解答!

如有转载,请注明出处,谢谢!

Hexo博客绑定域名

前段时间买了个域名,chinafish.news,36元/年,别问我为什么买了个后缀为.news的域名,我这也是没办法。

之间搭建了个博客,chinafishnews.gitcafe.io或者chinafishnews.github.io,欢迎访问。

博客如何绑定域名呢,以gitcafe为例。

按如下配置

然后登陆阿里云

域名处点击解析,按如下配置

配置完后,静待几分钟后,便发现可以使用购买的域名访问你的博客了~


如有任何疑问或问题请联系我:fishnewsdream@gmail.com,欢迎交流,共同提高!

Objective-C/Swift技术开发交流群201556264,讨论何种技术并不受限,欢迎各位大牛百家争鸣!

微信公众号OldDriverWeekly,欢迎关注并提出宝贵意见

老司机iOS周报,欢迎关注或订阅

刚刚在线工作室,欢迎关注或提出建设性意见!

刚刚在线论坛, 欢迎踊跃提问或解答!

如有转载,请注明出处,谢谢!

Xcode中的常用略带装逼的快捷键

开发人员的工作内容在很多外人眼里都是很神秘的存在,而作为开发又经常和产品、UI、运维等打交道,而这些人又以女人居多,而女人又是相信眼睛看到的多过大脑思考的物种,偶尔当她们在身旁时,脱离鼠标,“意外”的炫技也十分有必要。尽管可能最终什么也没实现,但是这个过程很重要,毕竟你看哥玩的这么大气精炼,想必也不是小菜,这在她们的心里定位都不是一个层级的,所以给大家介绍几个常用的,其实毫无难度的快捷键。

Xcode中或者Mac OS系统的快捷键多了去了,触控板用着也不能更爽,脱离鼠标操作也很容易。快捷键太多,这里就以图文的形式只给大家说几个我常用的Xcode中的快捷键,一些诸如缩进、注释、运行、停止、拍照、光标移动等快捷键我就不一一演示了,大家如果有觉得好的常用的装逼的快捷键欢迎告知。

commond+alt+< / commond+alt+> (折叠/展开代码)

commond+alt+shift+< /commond+alt+shift+> (全局折叠/展开代码)

commond+alt+[ / commond+alt+] (上移/下移代码)

commond+alt+return/commond+return (拆分)

commond+shift+= (更新约束)

commond+l (根据行数快速定位代码)

control+space (全局搜索)

commond+shift+o (快速打开)

commond+0 / commond+alt+0 / commond+shift+y (显示/关闭左右导航栏/控制台)

commond+shift+0(zero) (快速打开文档)

control+i (格式化代码)

commond+shift+</>+向上/向下箭头 (代码多选)

commond+shift+x (代码整理)

需使用xalign插件 下载地址:https://github.com/ChinaFishNews/XAlign.git

commond+n /commond+shift+n (新建文件/项目)

commond+k (清空控制台内容)

commond+shift+j (快速显示当前类所在项目中的位置)

commond+option+r (编辑配置Edit Scheme)

commond+control+a (QQ截屏,然后在对话框点击粘贴)

commond+control+空格 (打开emoji表情)

commond+[/] (显示上/下一层文件目录)

commond+shift+A (滚动截屏,前提是内容超出一屏,非Mac自带,而是snip软件)

commond+shift+. (隐藏/显示隐藏文件)


如有任何疑问或问题请联系我:fishnewsdream@gmail.com,欢迎交流,共同提高!

Objective-C/Swift技术开发交流群201556264,讨论何种技术并不受限,欢迎各位大牛百家争鸣!

微信公众号OldDriverWeekly,欢迎关注并提出宝贵意见

老司机iOS周报,欢迎关注或订阅

刚刚在线工作室,欢迎关注或提出建设性意见!

刚刚在线论坛, 欢迎踊跃提问或解答!

如有转载,请注明出处,谢谢!

将Hexo博客同时搭建在Github和Gitcafe上

Hexo博客是基于nodejs的,那么如何搭建呢,这里我选择了gitcafe和github,主要是国内用户访问github很慢,所以同时托管在这两个平台上。 整个搭建过程如下

1.安装nodejs。我选择了使用homebrew安装nodejs,如何安装brewhome呢?使用如下命令

1
ruby -e "$(curl -fsSL https://raw.github.com/Homebrew/homebrew/go/install)”

然后使用如下命令安装nodejs

1
brew install node

当然安装nodejs的方法有多种,可以使用git安装也可以下载源码( http://nodejs.org/download/ )自行安装。

2.安装Hexo

使用nodejs自带的npm安装,先cd到安装位置,然后使用如下命令

1
npm install -g hexo

1
hexo init
1
npm install

也可以下载源码自行安装( http://www.nodejs.org/download/)

3.安装git

现在的mac系统已经自带git了,不需要安装。当然如果没有安装git,可以使用homebrewa安装

1
sudo brew install git

同样也可以下载源码( https://www.kernel.org/pub/software/scm/git/ )自行安装

4.配置SSH key

使用如下命令生成私钥

1
ssh-keygen -t rsa

将生成的key(id_rsa.pub文件,添加到github和gitcafe上(Account Settings->SSH Public Keys),如果之前已经设置过则无需再次设置,主要是为了增加读写权限。

  1. 创建项目

在github和gitcafe上分别创建与用户名对应的仓库,仓库名为your_user_name.github.io和your_user_name

  1. 修改hexo根目录下_config.yml文件

我是同时托管在github和gitcafe上,做如下设置,ChinaFishNews需换成自己的用户名

1
2
3
4
5
deploy:
type: git
repository:
github: git@github.com:ChinaFishNews/ChinaFishNews.github.io.git
gitcafe: git@gitcafe.com:ChinaFishNews/ChinaFishNews.git,gitcafe-pages

如果只托管在github上这样设置

1
2
3
4
deploy:
type: git
repository: git@github.com:ChinaFishNews/ChinaFishNews.github.io.git
branch: master

如果只托管在gitcafe上这样设置

1
2
3
4
deploy:
type: git
repository: git@gitcafe.com:ChinaFishNews/ChinaFishNews.git
branch: gitcafe-pages

注意,:后面空一格,否则会失败,hexo语法极其严格,在使用markdown写博客的时候也要格外注意。

7 Start the server

hexo博客已搭建好了,可以cd到hexo目录 运行

1
hexo server

在浏览器中打开 http://localhost:4000/,这时可以看到Hexo已为你生成了一篇博客。

  1. 部署到服务器
    hexo server只是在本地浏览,这时候可以部署到服务器了,使用如下命令
1
hexo g
1
hexo d

这时候在浏览器上输入chinafishnews.gitcafe.io或者chinafishnews.github.io就可以访问你的博客了(chinafishnews替换为你的用户名)

常用写作命令

  • 建立新文章:hexo n “新文章名”
  • 预览文章:hexo s
  • 生成网页:hexo g
  • 发布文章:hexo d
  • 生成网页并发布文章:hexo d -g
  • 查看Hexo的版本: hexo version

书写博客

可以使用markdown软件书写博客,Mark案例如下http://mahua.jser.mehttps://www.zybuluo.com/mdeditor#fn:code可以参考学习

这是我的一篇博客的案例,titile为标题,data是发布日期,categories: OC指的是属于分类中的OC这一分类,tags指的是添加的标签,除title外剩下的不是必须的,但一但添加,格式必须书写正确,否则会发布失败。文件可随意编辑,语法极其严格,一定要多加注意!


如有任何疑问或问题请联系我:fishnewsdream@gmail.com,欢迎交流,共同提高!

Objective-C/Swift技术开发交流群201556264,讨论何种技术并不受限,欢迎各位大牛百家争鸣!

微信公众号OldDriverWeekly,欢迎关注并提出宝贵意见

老司机iOS周报,欢迎关注或订阅

刚刚在线工作室,欢迎关注或提出建设性意见!

刚刚在线论坛, 欢迎踊跃提问或解答!

如有转载,请注明出处,谢谢!

使用UIBezierPath和CAShapeLayer画各种图形

本文系转载

原作者: J0hnnny

原文地址: http://www.jianshu.com/p/c5cbb5e05075

CAShapeLayer是CALayer的子类,但是比CALayer更灵活,可以画出各种图形,当然,你也可以使用其他方式来画,随你。

杂谈

CAShapeLayer 中,也可以像 CALayer 一样指定它的 frame 来画,就像这样:

1
2
3
4
let layer = CAShapeLayer()
layer.frame = CGRectMake(110, 100, 150, 100)
layer.backgroundColor = UIColor.blackColor().CGColor
view.layer.addSublayer(layer)

然后你就会得到如图这样的黑色矩形

但是,CAShapeLayer 有一个神奇的属性 path 用这个属性配合上 UIBezierPath 这个类就可以达到超神的效果。

UIBezierPath 顾名思义,这是用贝塞尔曲线的方式来构建一段弧线,你可以用任意条弧线来组成你想要的形状,比如,你想用它来和上面一样画一个矩形,那就可以这样子来做:

1
2
3
4
5
let path = UIBezierPath(rect: CGRectMake(110, 100, 150, 100))
let layer = CAShapeLayer()
layer.path = path.CGPath
layer.fillColor = UIColor.blackColor().CGColor
view.layer.addSublayer(layer)

要注意的是,这里就不要用backgroundColor 这个属性了,而要使用 fillColorstrokeColor ,前者代表设置这个 Layer 的填充色,后者代表设置它的边框色

1
2
layer.fillColor = UIColor.clearColor().CGColor
layer.strokeColor = UIColor.blackColor().CGColor

可以试一下把上面代码设置颜色的部分改成这个样子,那么运行程序的时候就会是这种样子

###玩一下UIBezierPath

在说回 UIBezierPath ,在 UIBezierPath 的 init 方法中,就有很多方便你画各种图形的方法,比如你可以画一个带圆角的图形

1
2
3
4
5
let path = UIBezierPath(roundedRect: CGRectMake(110, 100, 150, 100), cornerRadius: 50)
let layer = CAShapeLayer()
layer.path = path.CGPath
layer.fillColor = UIColor.clearColor().CGColor
layer.strokeColor = UIColor.blackColor().CGColor

还可以指定起始角和半径画圆

1
2
3
4
5
6
7
8
let radius: CGFloat = 60.0
let startAngle: CGFloat = 0.0
let endAngle: CGFloat = CGFloat(M_PI * 2)
let path = UIBezierPath(arcCenter: view.center, radius: radius, startAngle: startAngle, endAngle: endAngle, clockwise: true)
let layer = CAShapeLayer()
layer.path = path.CGPath
layer.fillColor = UIColor.clearColor().CGColor
layer.strokeColor = UIColor.blackColor().CGColor

在这里涉及到角度的问题,起始角和结束角,这里的角度使使用弧度制来表示,这里我收藏了一张图片,以方便参考

怎么画曲线

贝塞尔曲线的画法是由起点、终点、控制点三个参数来画的,为了解释清楚这个点,我写了几行代码来解释它

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
let startPoint = CGPointMake(50, 300)
let endPoint = CGPointMake(300, 300)
let controlPoint = CGPointMake(170, 200)

let layer1 = CALayer()
layer1.frame = CGRectMake(startPoint.x, startPoint.y, 5, 5)
layer1.backgroundColor = UIColor.redColor().CGColor

let layer2 = CALayer()
layer2.frame = CGRectMake(endPoint.x, endPoint.y, 5, 5)
layer2.backgroundColor = UIColor.redColor().CGColor

let layer3 = CALayer()
layer3.frame = CGRectMake(controlPoint.x, controlPoint.y, 5, 5)
layer3.backgroundColor = UIColor.redColor().CGColor

let path = UIBezierPath()
let layer = CAShapeLayer()

path.moveToPoint(startPoint)
path.addQuadCurveToPoint(endPoint, controlPoint: controlPoint)

layer.path = path.CGPath
layer.fillColor = UIColor.clearColor().CGColor
layer.strokeColor = UIColor.blackColor().CGColor

view.layer.addSublayer(layer)
view.layer.addSublayer(layer1)
view.layer.addSublayer(layer2)
view.layer.addSublayer(layer3)

我很随意的定义了三个点,为了清楚显示它们的位置,我放了三个矩形在上面以便观察,然后调用 path.moveToPoint(startPoint) 让它移动到起始点,然后调用path.addQuadCurveToPoint(endPoint, controlPoint: controlPoint) 这个方法告诉它结束点和控制点,这样它就能画出一条有弧度的线条了,如果把fillColor设置一个颜色,那么它就会变成一个很丑的形状了,示例图如下

控制点决定了它的曲率,曲线的顶点不等于控制点的位置,具体可以看一下贝塞尔曲线的定义,你还可以使用两个控制点来画,两个控制点可以使用方法 path.addCurveToPoint(endPoint, controlPoint1: controlPoint, controlPoint2: controlPoint2)来搞定

这样它会是这个样子

再来说说 CAShapeLayer

CAShapeLayer 是个神奇的东西,给它一个path它就能变成你想要的形状,它还有很多可以玩的地方。综合使用可以组合成不同的动画,比如下面这样

这三个动画就是使用了 strokeEnd strokeStart lineWidth 三个属性,第一个动画用了strokeEnd这个属性的值范围是0-1,动画显示了从0到1之间每一个值对这条曲线的影响,strokeStart的方法则是相反的,如果把这两个值首先都设置成0.5然后慢慢改变成0和1的时候就会变成第二个动画,配合lineWidth则曲线会慢慢变粗,这里的很多属性都是支持动画的。

示例代码

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
private func animation1() {
let animation = CABasicAnimation(keyPath: "strokeEnd")
animation.fromValue = 0
animation.toValue = 1
animation.duration = 2
layer.addAnimation(animation, forKey: "")
}

private func animation2() {
layer.strokeStart = 0.5
layer.strokeEnd = 0.5

let animation = CABasicAnimation(keyPath: "strokeStart")
animation.fromValue = 0.5
animation.toValue = 0
animation.duration = 2

let animation2 = CABasicAnimation(keyPath: "strokeEnd")
animation2.fromValue = 0.5
animation2.toValue = 1
animation2.duration = 2

layer.addAnimation(animation, forKey: "")
layer.addAnimation(animation2, forKey: "")
}

private func animation3() {
let animation = CABasicAnimation(keyPath: "lineWidth")
animation.fromValue = 1
animation.toValue = 10
animation.duration = 2
layer.addAnimation(animation, forKey: "")
}

应用一下

前一阵子在仿时光网这个APP,其中有一个Layer的形状很怪异,是这样的

很明显它可以用 CAShapeLayer + UIBezierPath 来做,思路大概是这样,先移动到左上方的位置,然后向下划线,然后往右划线,然后往上划线,还剩一个盖子,这个盖子就用一个控制点控制曲率,非常简单,代码如下

1
2
3
4
5
6
7
8
9
10
11
12
13
let finalSize = CGSizeMake(CGRectGetWidth(view.frame), 400)
let layerHeight = finalSize.height * 0.2
let layer = CAShapeLayer()
let bezier = UIBezierPath()
bezier.moveToPoint(CGPointMake(0, finalSize.height - layerHeight))
bezier.addLineToPoint(CGPointMake(0, finalSize.height - 1))
bezier.addLineToPoint(CGPointMake(finalSize.width, finalSize.height - 1))
bezier.addLineToPoint(CGPointMake(finalSize.width, finalSize.height - layerHeight))
bezier.addQuadCurveToPoint(CGPointMake(0,finalSize.height - layerHeight),
controlPoint: CGPointMake(finalSize.width / 2, (finalSize.height - layerHeight) - 40))
layer.path = bezier.CGPath
layer.fillColor = UIColor.blackColor().CGColor
view.layer.addSublayer(layer)

就能画出这样的形状来

再来一个复杂点的,微信下拉拍小视频的那只眼睛很有趣,来模仿一下那个效果吧,它是这样的

首先你得画出这只眼睛,这是眼睛包括5个部分组成(这个是用OC写的)

1
2
3
4
5
@property (strong, nonatomic) CAShapeLayer *eyeFirstLightLayer;
@property (strong, nonatomic) CAShapeLayer *eyeSecondLightLayer;
@property (strong, nonatomic) CAShapeLayer *eyeballLayer;
@property (strong, nonatomic) CAShapeLayer *topEyesocketLayer;
@property (strong, nonatomic) CAShapeLayer *bottomEyesocketLayer;

然后,还是通过 UIBezierPathCAShapeLayer 这样的老套路来画,代码较多

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
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
- (CAShapeLayer *)eyeFirstLightLayer {
if (!_eyeFirstLightLayer) {
_eyeFirstLightLayer = [CAShapeLayer layer];
CGPoint center = CGPointMake(CGRectGetWidth(self.frame) / 2, CGRectGetHeight(self.frame) / 2);
UIBezierPath *path = [UIBezierPath bezierPathWithArcCenter:center
radius:CGRectGetWidth(self.frame) * 0.2
startAngle:(230.f / 180.f) * M_PI
endAngle:(265.f / 180.f) * M_PI
clockwise:YES];
_eyeFirstLightLayer.borderColor = [UIColor blackColor].CGColor;
_eyeFirstLightLayer.lineWidth = 5.f;
_eyeFirstLightLayer.path = path.CGPath;
_eyeFirstLightLayer.fillColor = [UIColor clearColor].CGColor;
_eyeFirstLightLayer.strokeColor = [UIColor whiteColor].CGColor;
}
return _eyeFirstLightLayer;
}

- (CAShapeLayer *)eyeSecondLightLayer {
if (!_eyeSecondLightLayer) {
_eyeSecondLightLayer = [CAShapeLayer layer];
CGPoint center = CGPointMake(CGRectGetWidth(self.frame) / 2, CGRectGetHeight(self.frame) / 2);
UIBezierPath *path = [UIBezierPath bezierPathWithArcCenter:center
radius:CGRectGetWidth(self.frame) * 0.2
startAngle:(211.f / 180.f) * M_PI
endAngle:(220.f / 180.f) * M_PI
clockwise:YES];
_eyeSecondLightLayer.borderColor = [UIColor blackColor].CGColor;
_eyeSecondLightLayer.lineWidth = 5.f;
_eyeSecondLightLayer.path = path.CGPath;
_eyeSecondLightLayer.fillColor = [UIColor clearColor].CGColor;
_eyeSecondLightLayer.strokeColor = [UIColor whiteColor].CGColor;

}
return _eyeSecondLightLayer;
}

- (CAShapeLayer *)eyeballLayer {
if (!_eyeballLayer) {
_eyeballLayer = [CAShapeLayer layer];
CGPoint center = CGPointMake(CGRectGetWidth(self.frame) / 2, CGRectGetHeight(self.frame) / 2);
UIBezierPath *path = [UIBezierPath bezierPathWithArcCenter:center
radius:CGRectGetWidth(self.frame) * 0.3
startAngle:(0.f / 180.f) * M_PI
endAngle:(360.f / 180.f) * M_PI
clockwise:YES];
_eyeballLayer.borderColor = [UIColor blackColor].CGColor;
_eyeballLayer.lineWidth = 1.f;
_eyeballLayer.path = path.CGPath;
_eyeballLayer.fillColor = [UIColor clearColor].CGColor;
_eyeballLayer.strokeColor = [UIColor whiteColor].CGColor;
_eyeballLayer.anchorPoint = CGPointMake(0.5, 0.5);

}
return _eyeballLayer;
}

- (CAShapeLayer *)topEyesocketLayer {
if (!_topEyesocketLayer) {
_topEyesocketLayer = [CAShapeLayer layer];
CGPoint center = CGPointMake(CGRectGetWidth(self.frame) / 2, CGRectGetHeight(self.frame) / 2);
UIBezierPath *path = [UIBezierPath bezierPath];
[path moveToPoint:CGPointMake(0, CGRectGetHeight(self.frame) / 2)];
[path addQuadCurveToPoint:CGPointMake(CGRectGetWidth(self.frame), CGRectGetHeight(self.frame) / 2)
controlPoint:CGPointMake(CGRectGetWidth(self.frame) / 2, center.y - center.y - 20)];
_topEyesocketLayer.borderColor = [UIColor blackColor].CGColor;
_topEyesocketLayer.lineWidth = 1.f;
_topEyesocketLayer.path = path.CGPath;
_topEyesocketLayer.fillColor = [UIColor clearColor].CGColor;
_topEyesocketLayer.strokeColor = [UIColor whiteColor].CGColor;
}
return _topEyesocketLayer;
}

- (CAShapeLayer *)bottomEyesocketLayer {
if (!_bottomEyesocketLayer) {
_bottomEyesocketLayer = [CAShapeLayer layer];
CGPoint center = CGPointMake(CGRectGetWidth(self.frame) / 2, CGRectGetHeight(self.frame) / 2);
UIBezierPath *path = [UIBezierPath bezierPath];
[path moveToPoint:CGPointMake(0, CGRectGetHeight(self.frame) / 2)];
[path addQuadCurveToPoint:CGPointMake(CGRectGetWidth(self.frame), CGRectGetHeight(self.frame) / 2)
controlPoint:CGPointMake(CGRectGetWidth(self.frame) / 2, center.y + center.y + 20)];
_bottomEyesocketLayer.borderColor = [UIColor blackColor].CGColor;
_bottomEyesocketLayer.lineWidth = 1.f;
_bottomEyesocketLayer.path = path.CGPath;
_bottomEyesocketLayer.fillColor = [UIColor clearColor].CGColor;
_bottomEyesocketLayer.strokeColor = [UIColor whiteColor].CGColor;

}
return _bottomEyesocketLayer;
}

然后更改一下某些属性的值,方便稍后的动画

1
2
3
4
5
6
7
8
9
- (void)setupAnimation {
self.eyeFirstLightLayer.lineWidth = 0.f;
self.eyeSecondLightLayer.lineWidth = 0.f;
self.eyeballLayer.opacity = 0.f;
_bottomEyesocketLayer.strokeStart = 0.5f;
_bottomEyesocketLayer.strokeEnd = 0.5f;
_topEyesocketLayer.strokeStart = 0.5f;
_topEyesocketLayer.strokeEnd = 0.5f;
}

最后根据 UIScrollViewcontentOffset 来控制各种属性,办法较笨,但管用。

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
- (void)animationWith:(CGFloat)y {
CGFloat flag = self.frame.origin.y * 2.f - 20.f;
if (y < flag) {
if (self.eyeFirstLightLayer.lineWidth < 5.f) {
self.eyeFirstLightLayer.lineWidth += 1.f;
self.eyeSecondLightLayer.lineWidth += 1.f;
}
}

if(y < flag - 20) {
if (self.eyeballLayer.opacity <= 1.0f) {
self.eyeballLayer.opacity += 0.1f;
}

}

if (y < flag - 40) {
if (self.topEyesocketLayer.strokeEnd < 1.f && self.topEyesocketLayer.strokeStart > 0.f) {
self.topEyesocketLayer.strokeEnd += 0.1f;
self.topEyesocketLayer.strokeStart -= 0.1f;
self.bottomEyesocketLayer.strokeEnd += 0.1f;
self.bottomEyesocketLayer.strokeStart -= 0.1f;
}
}

if (y > flag - 40) {
if (self.topEyesocketLayer.strokeEnd > 0.5f && self.topEyesocketLayer.strokeStart < 0.5f) {
self.topEyesocketLayer.strokeEnd -= 0.1f;
self.topEyesocketLayer.strokeStart += 0.1f;
self.bottomEyesocketLayer.strokeEnd -= 0.1f;
self.bottomEyesocketLayer.strokeStart += 0.1f;
}
}

if (y > flag - 20) {
if (self.eyeballLayer.opacity >= 0.0f) {
self.eyeballLayer.opacity -= 0.1f;
}
}

if (y > flag) {
if (self.eyeFirstLightLayer.lineWidth > 0.f) {
self.eyeFirstLightLayer.lineWidth -= 1.f;
self.eyeSecondLightLayer.lineWidth -= 1.f;
}
}
}

最后

总之使用 UIbezierPathCAShapeLayer 可以画出你想要的任何形状,没有它做不到,只有你想不到,搞定了它们你就可以轻松定制你想要的任何控件了。

iOS性能调优-使用Instruments诊断App

Instruments是Xcode提供的一个强大的工具,Allocations,Leaks,Time Profiler被戏称为Instruments的救命三招。Alocations通常用来跟踪app内存使用情况,Leaks用来检查app运行时产生的内存泄露,Time profiler用来帮助我们分析代码的执行时间,找出程序变慢的原因。

本来想写一篇总结Instruments下各工具使用的博客,网上查了下,资料已经很丰富,讲解的也远比我想讲的要好的多,最主要的是,写博客太费时间,尤其是长篇博客,在此,对那些乐此不疲产生优质文章的博主、作者致以崇高的敬意,感谢你们的劳动成果让开发者们受益!

下面这篇文章讲得比价全面,可以自行阅读探索

如何使用Instruments诊断App(Swift版)


如有任何错误之处或疑问,请联系我:fishnewsdream@gmail.com,欢迎交流,共同提高!

Objective-C/Swift技术开发交流群201556264,讨论何种技术并不受限,欢迎各位大牛百家争鸣!

微信公众号OldDriverWeekly,欢迎关注并提出宝贵意见

老司机iOS周报,欢迎关注或订阅

刚刚在线工作室,欢迎关注或提出建设性意见!

刚刚在线论坛, 欢迎踊跃提问或解答!

iOS崩溃调试的多种方法

在iOS开发调试及上线后,程序都经常需要调试,简单点来说开发时打断点,复杂的情况下需要分析crash文件,尤其是上线后也需要修复崩溃的bug。

获取崩溃信息有多种方法。一般来说有如下几种

  • 自己实现应用内崩溃收集,也可上传服务器

  • 使用苹果提供的Carsh崩溃收集服务

  • Xcode自带的查看设备崩溃信息

  • 使用第三方统计工具

自己实现应用内崩溃收集

苹果提供了异常处理的类,NSException,这个类可以创建及获取一个异常对象。

使用苹果提供的Carsh崩溃收集服务

苹果在Xcode中为我们集成了崩溃统计功能,在Window->Organizer->Crashes中可以看到

但是,苹果自带的这个崩溃统计工具需要在手机上额外设置。
设置->隐私->诊断与用量->诊断与用户数据(iOS8以下在通用中设置),选择自动发送并与开发者分享即可。

Xcode自带的查看设备崩溃信息

打开Xcode,选择Windows-> Devices -> 选择自己的手机 -> View Device Logs 就可以查看我们的崩溃信息。

如果手机上的应用是这台电脑打包安装的,这样崩溃信息已经为我们符号化好了,点击去之后,如果还是没有符号化完毕 ,我们选择文件,然后右击选择Re-Sysbomlicate就可以。如果是使用其他电脑进行的打包,我们可以在这里面将Crash文件导出,自己通过命令行的方式进行解析。

使用第三方统计工具

之前使用过友盟,还需要使用工具自行解析,感觉并不是很好,还有比如百度统计,BugHD,Fabric等很多。崩溃收集统计函数应该只进行一次调用,如果用第三方的话也最好只用一个第三方,这样我们获取崩溃统计信息的途径也是唯一的。第三方统计工具并不是用的越多越好,使用多个崩溃收集第三方会导致NSSetUncaughtExceptionHandler()函数指针的恶意覆盖,导致有些第三方不能收到崩溃信息。

我现在在用的是Fabric,感觉相当不错,下篇文章再做讲解。另外BugHD也还是不错,就是延迟太久才能收到.使用BugHD,需前往官网注册,创建项目,然后集成代码,整个流程非常简单。

1.下载并导入 SDK 下载 SDK

将下载包中的 BugHD.framework 文件夹拖到 Xcode 项目中,在应用设置中, Build Phases -> Link Binary With Libraries 里添加SystemConfiguration.framework,当然也可以通过Cocoapods安装,官网那个有详细的使用文档。

2 在 AppDelegate.m 中导入头文件:

#import \ //导入头文件
然后在

application:didFinishLaunchingWithOptions: 方法中加入一行:

[BugHD handleCrashWithKey:@”你的GENERAL_KEY”]; 即可。

GENERAL_KEY在创建项目时会自动生成。默认是在release模式下词汇收集错误信息,会将错误信息显示在官网并会发到注册邮箱里。Debug模式下也希望收到错误信息的话,需要设置

捕捉到的错误信息

但是这个错误信息延迟的太久,可能需要半天甚至一天的时间才能收集到。

dSYM

上述中提到的dSYM,是一种文件格式。我们每次Archive之后,都会生成一个dSYM文件,也就是符号集。符号集是我们打包之后,和.app文件同级的后缀名为.dSYM的文件,这个文件必须使用Xcode进行打包才有。每一个.dSYM文件都有一个UUID,和.app文件中的UUID对应,代表着是一个应用。而.dSYM文件中每一条崩溃信息也有一个单独的UUID,用来和程序的UUID进行校对。符号集中存储着文件名、方法名、行号的信息,是和可执行文件的16进制函数地址对应的,通过分析崩溃的.Crash文件可以准确知道具体的崩溃信息。必须使用当前应用打包的电脑所生成的dSYM文件,其他电脑生成的文件可能会导致分析不准确。

崩溃分析

这个崩溃分析我自己并没有实现,觉得比较繁琐,在使用友盟的时候,也需要使用错误分析工具来实现。以下,是网上找的一个方法,可以自行参考。

通过Mac自带的命令行工具解析Crash文件需要具备三个文件

  • symbolicatecrash,Xcode自带的崩溃分析工具,使用这个工具可以更精确的定位崩溃所在的位置,将0x开头的地址替换为响应的代码和具体行数。

  • 我们打包时产生的dSYM文件。

  • 崩溃时产生的Crash文件

在解析崩溃信息的时候,首先在桌面上建立一个Crash文件夹,然后将.Crash、.dSYM、symbolicatecrash放在这个文件夹中,这样进入这个文件夹下,直接一行命令就解决了。

symbolicatecrash我们可以在下面路径下可以找到,我用的是Xcode7,其他版本Xcode路径可能不一样,请自行查找。

1
/Applications/Xcode.app/Contents/SharedFrameworks/DTDeviceKitBase.framework/Versions/A/Resources/symbolicatecrash

然后Window->Organizer->Archives中,选中archive的版本右击,选择Show in Finder就可以获取dSYM文件了。

将.Crash、.dSYM、symbolicatecrash三个文件都放在我们在桌面建立的Crash文件夹中。

开启命令行工具,进入崩溃文件夹中

cd /Users/username/Desktop/崩溃文件夹

使用命令解析Crash文件

./symbolicatecrash ./.crash ./.app.dSYM > symbol.crash

如果上面命令不成功,使用命令检查一下环境变量

xcode-select -print-path

返回结果:

/Applications/Xcode.app/Contents/Developer/

如果不是上面的结果,需要使用下面命令设置一下导出的环境变量,然后重复上面解析的操作。

export DEVELOPER_DIR=/Applications/XCode.app/Contents/Developer

解析完成后会生成一个新的.Crash文件,这个文件中就是崩溃详细信息。图中红色标注的部分就是我们代码崩溃的部分。

注意,以下情况不会有崩溃信息产生:

  • 内存访问错误(不是野指针错误)

  • 低内存,当程序内存使用过多会造成系统低内存的问题,系统会将程序内存回收

  • 因为某种原因触发看门狗机制


如有任何疑问或问题请联系我:fishnewsdream@gmail.com,欢迎交流,共同提高!

Objective-C/Swift技术开发交流群201556264,讨论何种技术并不受限,欢迎各位大牛百家争鸣!

微信公众号OldDriverWeekly,欢迎关注并提出宝贵意见

老司机iOS周报,欢迎关注或订阅

刚刚在线工作室,欢迎关注或提出建设性意见!

刚刚在线论坛, 欢迎踊跃提问或解答!

如有转载,请注明出处,谢谢!

Crash捕捉工具-Fabric

上篇文章提到了多种调试记录错误日志的方法。我现在在用的是Fabric,是Twitter的一个工具,目前来看效果不错。下面来看下如何集成并使用。

前往官网,,先注册账号。

Fabric安装包下载链接:http://pan.baidu.com/s/1qX0Ab96 密码:b8sq

下载安装


打开Fabric并选中项目,然后在Crashlytics选项点击Installed



复制白色部分到xcode中


继续点击Next

可拖拽按钮至Xcode中,拖拽成功之后可发现项目中多了Fabric.framework和Crashlytics.framwork。这一步也可以使用pod安装

安装完后按如下集成代码

至此集成完毕。

默认只收集release模式下的错误日志,怎么在Debug模式下也收集呢?可以这样设置

这样在调试和发布后如有遇到崩溃,都会在官网显示,并发往注册邮箱。



注意:Fabric的原理还是把发布后的dsym上传后对它进行定位,显示出错误的位置。由于版本和系统可能并不一致,集成过程如果步骤有偏差需按照Fabric上显示的的步骤集成。


如有任何疑问或问题请联系我:fishnewsdream@gmail.com,欢迎交流,共同提高!

Objective-C/Swift技术开发交流群201556264,讨论何种技术并不受限,欢迎各位大牛百家争鸣!

微信公众号OldDriverWeekly,欢迎关注并提出宝贵意见

老司机iOS周报,欢迎关注或订阅

刚刚在线工作室,欢迎关注或提出建设性意见!

刚刚在线论坛, 欢迎踊跃提问或解答!

如有转载,请注明出处,谢谢!

谷歌浏览器翻墙插件

红杏已经彻底无法使用了,新推出了SS(Shadowsocks),价格如下


虽说不是很贵,然而也并不是很便宜。

其他的一些vpn比如云梯、Astrill等也均需要付费,稳定性也不太好。价格如下

我现在在用的是Astrill VPN, pc端和移动端均有astrill软件可供下载,比较方便,性能也还说的过去。当然金钱紧张的我肯定是不会买这么奢侈的东西了,用的之前一朋友的。

以上,都需要钱的,有没有免费的呢,有,叫“壁虎漫步”。

壁虎漫步是chrome的插件,和红杏有点像,没有会员功能,目前是免费的。试了下,效果可以接受。

插件下载地址 密码:rcan
下载 密码be3q

把下载好的插件拖到chrome浏览器,需要注册账号。

使用壁虎漫步的过程中,可以开启“自动切换模式”,遇到有打开障碍或者速度很慢的网站,就一键“添加规则”,将域名加入到壁虎漫步的规则列表中。这样的话,当访问在规则列表中的网站的时候,就会自动启用壁虎;而访问不在规则列表中的网站时,就自动使用直接连接。既不影响国内网站的速度,又不影响国外网站的访问,只需要初次遭遇访问障碍的时候添加规则,后续不用进行任何操作。

亲测可用,虽然有点不稳定,谁让它是免费的呢。

之前不知道什么原因下载了蓝灯(lantern),一直没理会,近来正好听一小伙伴提及,查了下,竟然可以翻墙,而且用法极其简单,直接打开运行即可使用。

Lantern是免费的桌面程序,用户可以流畅的访问被封锁的互联网站点。Lantern可以自动检测一个网站是否被封锁,对被封锁的网站,Lantern通过自有的服务器或未封锁地区的用户运行的Lantern来提供访问。对未封锁的网站不做影响。下载安装Lantern后,会在右上方的菜单栏出现。只要这个图标在,就表示Lantern正在运行,就可以用浏览器访问被封锁网站,如果不想使用,一定要正常退出Lantern,点击图标选择‘quit lantern’。如果是非正常退出,可能会使浏览器的代理设置改不过来,导致浏览器无法上网,解决办法是重新运行Lantern再正常退出即可。

Lantern下载

蓝灯也不能用了,讲道理,很是蛋疼

然而有什么问题是能难住天朝广大同胞的呢,我想是没有

使用萤火虫firefly也可以翻墙,使用方法和蓝灯一样

Firefly下载


如有任何错误之处或疑问,请联系我:fishnewsdream@gmail.com,欢迎交流,共同提高!

Objective-C/Swift技术开发交流群201556264,讨论何种技术并不受限,欢迎各位大牛百家争鸣!

微信公众号OldDriverWeekly,欢迎关注并提出宝贵意见

老司机iOS周报,欢迎关注或订阅

刚刚在线工作室,欢迎关注或提出建设性意见!

刚刚在线论坛, 欢迎踊跃提问或解答!

如有转载,请注明出处,谢谢!

本站总访问量 本文总阅读量