南风


  • 首页

  • 分类

  • 归档

  • 标签

  • 搜索
close

Vim命令合集

发表于 2015-09-24   |   分类于 IT随笔

命令历史

以:和/开头的命令都有历史纪录,可以首先键入:或/然后按上下箭头来选择某个历史命令。

启动vim

在命令行窗口中输入以下命令即可

vim 直接启动vim

vim filename 打开vim并创建名为filename的文件

文件命令

打开单个文件

vim file

同时打开多个文件

vim file1 file2 file3 ...

在vim窗口中打开一个新文件

:open file

在新窗口中打开文件

:split file

切换到下一个文件

:bn

切换到上一个文件

:bp

查看当前打开的文件列表,当前正在编辑的文件会用[]括起来。

:args

打开远程文件,比如ftp或者share folder

:e ftp://192.168.10.76/abc.txt
:e \\qadrive\test\1.txt

Vim的模式

  • 正常模式(按Esc或Ctrl+[进入) 左下角显示文件名或为空
  • 插入模式(按i键进入) 左下角显示–INSERT–
  • 可视模式(不知道如何进入) 左下角显示–VISUAL–

导航命令

% 括号匹配

插入命令

i 在当前位置生前插入

I 在当前行首插入

a 在当前位置后插入

A 在当前行尾插入

o 在当前行之后插入一行

O 在当前行之前插入一行

查找命令

/text  查找text,按n健查找下一个,按N健查找前一个。

?text  查找text,反向查找,按n健查找下一个,按N健查找前一个。

vim中有一些特殊字符在查找时需要转义  .*[]^%/?~$

:set ignorecase  忽略大小写的查找

:set noignorecase  不忽略大小写的查找

查找很长的词,如果一个词很长,键入麻烦,可以将光标移动到该词上,按*或#键即可以该单词进行搜索,相当于/搜索。而#命令相当于?搜索。

:set hlsearch  高亮搜索结果,所有结果都高亮显示,而不是只显示一个匹配。

:set nohlsearch  关闭高亮搜索显示

:nohlsearch  关闭当前的高亮显示,如果再次搜索或者按下n或N键,则会再次高亮。

:set incsearch  逐步搜索模式,对当前键入的字符进行搜索而不必等待键入完成。

:set wrapscan  重新搜索,在搜索到文件头或尾时,返回继续搜索,默认开启。

替换命令

ra 将当前字符替换为a,当期字符即光标所在字符。

s/old/new/ 用old替换new,替换当前行的第一个匹配

s/old/new/g 用old替换new,替换当前行的所有匹配

%s/old/new/ 用old替换new,替换所有行的第一个匹配

%s/old/new/g 用old替换new,替换整个文件的所有匹配

:10,20 s/^/    /g 在第10行知第20行每行前面加四个空格,用于缩进。

ddp 交换光标所在行和其下紧邻的一行。

移动命令

h 左移一个字符
l 右移一个字符,这个命令很少用,一般用w代替。
k 上移一个字符
j 下移一个字符

以上四个命令可以配合数字使用,比如20j就是向下移动20行,5h就是向左移动5个字符,在Vim中,很多命令都可以配合数字使用,比如删除10个字符10x,在当前位置后插入3个!,3a!,这里的Esc是必须的,否则命令不生效。

w 向前移动一个单词(光标停在单词首部),如果已到行尾,则转至下一行行首。此命令快,可以代替l命令。

b 向后移动一个单词 2b 向后移动2个单词

e,同w,只不过是光标停在单词尾部

ge,同b,光标停在单词尾部。

^ 移动到本行第一个非空白字符上。

0(数字0)移动到本行第一个字符上,

<HOME> 移动到本行第一个字符。同0健。

$ 移动到行尾 3$ 移动到下面3行的行尾

gg 移动到文件头。 = [[

G(shift + g) 移动到文件尾。 = ]]

f(find)命令也可以用于移动,fx将找到光标后第一个为x的字符,3fd将找到第三个为d的字符。

F 同f,反向查找。

跳到指定行,冒号+行号,回车,比如跳到240行就是 :240回车。另一个方法是行号+G,比如230G跳到230行。

Ctrl + e 向下滚动一行

Ctrl + y 向上滚动一行

Ctrl + d 向下滚动半屏

Ctrl + u 向上滚动半屏

Ctrl + f 向下滚动一屏

Ctrl + b 向上滚动一屏

撤销和重做

u 撤销(Undo)
U 撤销对整行的操作
Ctrl + r 重做(Redo),即撤销的撤销。

删除命令

x 删除当前字符

3x 删除当前光标开始向后三个字符

X 删除当前字符的前一个字符。X=dh

dl 删除当前字符, dl=x

dh 删除前一个字符

dd 删除当前行

dj 删除上一行

dk 删除下一行

10d 删除当前行开始的10行。

D 删除当前字符至行尾。D=d$

d$ 删除当前字符之后的所有字符(本行)

kdgg 删除当前行之前所有行(不包括当前行)

jdG(jd shift + g)   删除当前行之后所有行(不包括当前行)

:1,10d 删除1-10行

:11,$d 删除11行及以后所有的行

:1,$d 删除所有行

J(shift + j)  删除两行之间的空行,实际上是合并两行。

拷贝和粘贴

yy 拷贝当前行

nyy 拷贝当前后开始的n行,比如2yy拷贝当前行及其下一行。

p  在当前光标后粘贴,如果之前使用了yy命令来复制一行,那么就在当前行的下一行粘贴。

shift+p 在当前行前粘贴

:1,10 co 20 将1-10行插入到第20行之后。

:1,$ co $ 将整个文件复制一份并添加到文件尾部。

正常模式下按v(逐字)或V(逐行)进入可视模式,然后用jklh命令移动即可选择某些行或字符,再按y即可复制

ddp交换当前行和其下一行

xp交换当前字符和其后一个字符

剪切命令

正常模式下按v(逐字)或V(逐行)进入可视模式,然后用jklh命令移动即可选择某些行或字符,再按d即可剪切

ndd 剪切当前行之后的n行。利用p命令可以对剪切的内容进行粘贴

:1,10d 将1-10行剪切。利用p命令可将剪切后的内容进行粘贴。

:1, 10 m 20 将第1-10行移动到第20行之后。

退出命令

:wq 保存并退出

ZZ 保存并退出

:q! 强制退出并忽略所有更改

:e! 放弃所有修改,并打开原来文件。

窗口命令

:split或new 打开一个新窗口,光标停在顶层的窗口上

:split file或:new file 用新窗口打开文件

split打开的窗口都是横向的,使用vsplit可以纵向打开窗口。

Ctrl+ww 移动到下一个窗口

Ctrl+wj 移动到下方的窗口

Ctrl+wk 移动到上方的窗口

关闭窗口

:close 最后一个窗口不能使用此命令,可以防止意外退出vim。

:q 如果是最后一个被关闭的窗口,那么将退出vim。

ZZ 保存并退出。

关闭所有窗口,只保留当前窗口

:only

录制宏

按q键加任意字母开始录制,再按q键结束录制(这意味着vim中的宏不可嵌套),使用的时候@加宏名,比如qa。。。q录制名为a的宏,@a使用这个宏。

执行shell命令

:!command

:!ls 列出当前目录下文件

:!perl -c script.pl 检查perl脚本语法,可以不用退出vim,非常方便。

:!perl script.pl 执行perl脚本,可以不用退出vim,非常方便。

:suspend或Ctrl - Z 挂起vim,回到shell,按fg可以返回vim。

注释命令

perl程序中#开始的行为注释,所以要注释某些行,只需在行首加入#

3,5 s/^/#/g 注释第3-5行

3,5 s/^#//g 解除3-5行的注释

1,$ s/^/#/g 注释整个文档。

:%s/^/#/g 注释整个文档,此法更快。

帮助命令

:help or F1 显示整个帮助
:help xxx 显示xxx的帮助,比如 :help i, :help CTRL-[(即Ctrl+[的帮助)。
:help 'number' Vim选项的帮助用单引号括起
:help <Esc> 特殊键的帮助用<>扩起
:help -t Vim启动参数的帮助用-
:help i_<Esc> 插入模式下Esc的帮助,某个模式下的帮助用模式_主题的模式
帮助文件中位于||之间的内容是超链接,可以用Ctrl+]进入链接,Ctrl+o(Ctrl + t)返回

其他非编辑命令

. 重复前一次命令

:set ruler?  查看是否设置了ruler,在.vimrc中,使用set命令设制的选项都可以通过这个命令查看

:scriptnames  查看vim脚本文件的位置,比如.vimrc文件,语法文件及plugin等。

:set list 显示非打印字符,如tab,空格,行尾等。如果tab无法显示,请确定用set lcs=tab:>-命令设置了.vimrc文件,并确保你的文件中的确有tab,如果开启了expendtab,那么tab将被扩展为空格。

Vim教程
在Unix系统上
$ vimtutor
在Windows系统上
:help tutor

:syntax 列出已经定义的语法项
:syntax clear 清除已定义的语法规则
:syntax case match 大小写敏感,int和Int将视为不同的语法元素
:syntax case ignore 大小写无关,int和Int将视为相同的语法元素,并使用同样的配色方案

本文转自WWDC 2015: AUTO LAYOUT IMPROVEMENTS。

WWDC 2015: AUTO LAYOUT在iOS 9上的改进

发表于 2015-09-23   |   分类于 IT随笔

自从AUTO LAYOUT在iOS 6中引入以来,我一直深深的为之着迷,特别是通过直接在代码中使用它,而不是使用故事板。但它在代码中使用非常冗长。我写了一些类,使代码更加紧凑。但我不满意我的解决方案。所以我计划在WWDC期间去一个实验室,咨询一个苹果AUTO LAYOUT工程师对这个问题的看法。但是事实证明我不需要!苹果解决了大部分我在AUTO LAYOUT中遇到的问题在iOS 9的API中!在这篇文章中我想突出的新API更容易使用自动布局在代码和故事板! 在这片文章中,我将分别用代码和Storyboard展示用新的API使用AUTO LAYOUT是如何简单易用。

什么是AUTO LAYOUT

对于那些AUTO LAYOUT的新手,我想快速的过一下这东西到底是什么。AUTO LAYOUT是一个机制,用它可以很容易地支持不同的屏幕尺寸。
AUTO LAYOUT的核心是极其简单的。它使用“约束”来确定视图在屏幕上的x,y,宽度和高度属性。约束是描述一个视图的位置和大小的规则。一个视图需要多个约束来正确的定位和限制大小。约束和所代表它的类youtConstraint仅仅是遵循这个公式:

view1.attribute1 = view2.attribute2 x A + B

这是AUTO LAYOUT的核心,所有的约束都遵循这种模式。使用一系列遵循这种模式的约束你可以布局一切,它将在巧妙的缩放来适应不同的屏幕尺寸。
例如:

label.Top = container.Top x 1 + 20(列出了一个标签的y值低于容器的顶部边缘视图20像素点)
label.Width = container.Width x 0.5 + 0 (一个标签的宽度设置为一半的容器的宽度)

为什么使用AUTO LAYOUT?

在很长的一段时间内,iOS应用程序并没有在关心屏幕大小适配。iPhone 3g,4和4s基本上都是分辨率为320×480的逻辑点。随着视网膜屏幕的引入并没有改变,因为作为一名开发人员你仍然可以假装屏幕是320×480,而系统会为你转换为640×960。当然你也有iPad,但你不必为之做更多的工作,因为你将为iPad设计一个特定的用户界面,这将是特定的屏幕分辨率1024×768。

支持不同的分辨率

随着iPhone 4s到来的iOS 6.0,给我们介绍了自动布局。我们不觉得有必要使用它,但在它的目的很明显:使它容易支持iPhone更大的屏幕!在那一刻唯一的真正好处来自屏幕的旋转,从竖屏到横屏,这实际上也是一个分辨率的变化。

iPad的多任务模式

随着iOS 9的到来,AUTO LAYOUT变得如此重要的一个原因是:在iPad上支持多任务!现在你可以观看并排的两个应用程序在同一时间,这意味着应用程序要能够缩放自己的尺寸为四分之一屏幕或者半个屏幕。用户决定显示每个应用程序的大小。使用AUTO LAYOUT可以很容易适应这些变化。

STACKING VIEWS

Before iOS 9, we had to add many different constraints to all different views within a single screen to position them correctly and let them handle screen size changes accordingly. This was easy, but a little hard to manage. There were two ways to do it:

在iOS 9之前,我们不得不在一个屏幕上对所有子视图添加许多不同的约束来使它们适应屏幕大小的变化。这是一件简单的事情,但是难于管理。有两种方式可以实现:

  • 使用 storyboard
  • 使用代码

Storyboard

storyboard

使用故事板可以单击并拖动来创建约束,你最终将得到的大量的蓝线,这代表了约束。现在你想要插入另一个标签,在“车库乐队”和“苹果”之间。你该怎么做?你删除一些约束连接现有的标签,插入你的新标签和你现有的两个标签连接到你的新标签。这足以说明约束维护的复杂性。

用代码实现约束

用代码实现的话也存在同样的问题,这里没有蓝线,取而代之的是:

view.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat(
"V:|[titleLabel]-padding-[descriptionLabel]-padding-[imageView]", 
options: nil,
 metrics: ["padding": 10],
  views: [
          "titleLabel": titleLabel,
          "descriptionLabel": descriptionLabel,
          "imageView": imageView])
)
view.addConstraint(NSLayoutConstraint(
   item: titleLabel,
   attribute: .Leading,
   relatedBy: .Equal,
   toItem: self,
   attribute: .Leading,
   multiplier: 1,
   constant: 10)
)

这仍然不是最佳的管理方案。

UIStackView

随着iOS 9的一声炮响,UIStackView应运而生!你可以把一组子视图放入UIStackView,并将它们垂直或水平布局,这不费吹灰之力。不再需要为每个子视图添加约束。这一切UIStackView都已经为你做好。

在上边儿的例子中你只需要标示那里需要使用stack view。你只需找出子视图需要堆积的位置。几乎所有你能想到的UI都可以都可以通过嵌套stack views的方式建立视图。苹果强烈建议我们为每一个布局使用stack views,只有那些用stack views实在无法实现的才需要用单独的约束。

使用stack view的示例:

let stackView = UIStackView(arrangedSubviews: [titleLabel, descriptionLabel, imageView])
stackView.distribution = .Fill
stackView.alignment = .Leading
stackView.axis = .Vertical
stackView.spacing = 10

就是这样!在titleLabel和descriptionLabel之间添加一个label就像将其添加到数组的“arrangedSubviews”一样简单!
一个额外的好处:你可以很容易地通过动画动画隐藏/显示视图通过修改UIView的隐藏属性,而该属性通常不能做成动画。

stackview

所有需要的是修改动画的隐藏属性,如下:

UIView.animateWithDuration(0.5, animations: {
   someSubview.hidden = true
})

我自己实现的UIStackView

多么完美的UIStackView,但是它只能用在iOS 9及以上版本。但是我想用在iOS 7和iOS 8之中。UIStackView的接口看起来足够简单:用一个视图数组初始化它,配置它的一些属性如‘distribution’, ‘alignment’ 和 ‘axis’。这就是它!我想,这有多难?然而事实证明它比我想象的要难得多,但是我做到了!我完全重写了整个过程咋iOS 7和iOS 8之下。我为之自豪:TZStackView!
TZStackView git地址

我将它设计为和UIStackView一模一样的接口,以便于将来某一天被替代。使用TZStackView的实现上面的例子:

let stackView = TZStackView(arrangedSubviews: [titleLabel, descriptionLabel, imageView])
stackView.distribution = .Fill
stackView.alignment = .Leading
stackView.axis = .Vertical
stackView.spacing = 10

LAYOUT GUIDES

另一个新的iOS 9Auto Layout的概念是“layout guide”。是“constrain negative space”。什么意思?看个例子:
你有三个固定宽度的视图用来填补可用空间,你想让这些矩形之间的间距相等。

layout guides

The empty space in between the boxes is called ‘negative space’ and you want to express using constraints that you want those spaces to be equal to one another. Long story short: you can’t express that directly because constraints can only be applied on views, not on margins between those views. Before iOS 9 what you could do is add 4 transparent subviews in between those boxes, also known as ‘spacer views’ and put constraints on those. That works like a charm!

The problem with this approach is that it’s kind of a hack. You pollute your view hierarchy with things that are just there to position other views with no purpose of their own. This also impacts performance.

This brings me to layout guides, represented by the UILayoutGuide class. You can add them to your view like this:

视图之间的空的空间被称为“negative space”,你的目的是使用约束来使这些空间相等。长话短说:你不能直接表达,因为约束只能应用于视图,而不是那些视图之间的间距。在iOS 9之前你可以做的是添加4个透明子视图在这些视图之间,这些也被称为“间隔视图”,然后给这些视图添加约束。
这种方法的问题在于它是一种黑客技术。这污染了你的视图层次,它们仅仅是为了固定其他视图而没有自己的意义。这也影响了性能。
为此,引入了“layout guide”,由UILayoutGuide类来实现。你可以将它们添加到你的视图,像这样:

let layoutGuide = UILayoutGuide()
view.addLayoutGuide(layoutGuide)

Next, you can use the layout guide in your constraints, just as you would do using ‘spacer views’.

接下来,你可以在你的约束中使用layout guide,就像使用‘spacer views’。

view.addConstraint(NSLayoutConstraint(
         item: layoutGuide1,
    attribute: .Width,
    relatedBy: .Equal,
       toItem: layoutGuide2,
    attribute: .Width,
   multiplier: 1,
     constant: 0)
 )

这样做的好处是,我们不污染我们的视图层次和替换‘spacer views’用更轻量级的‘layout guides’。它们不能回应触摸或直观地呈现在屏幕上。它们只是在那里给其他视图提供约束。

CONSTRAINTS FLUENT INTERFACE

这也是一个功能在不久的将来会普遍使用的功能。它在WWDC的两节演讲中被提到。它简化了你创建单独约束的过程。在此重复我之前给出的一个例子:

view.addConstraint(NSLayoutConstraint(
      item: titleLabel,
 attribute: .Leading,
 relatedBy: .Equal,
    toItem: self,
 attribute: .Leading,
multiplier: 1,
  constant: 10)
)

现在你可以用下边儿的代码来达到同样的效果:

view.leadingAnchor.constraintEqualToAnchor(titleLabel.leadingAnchor, constant: 10)    

当我第一次看到这种新的写约束的方式时我非常激动。易读、易记忆更易于管理。这和UIStackView配合使用将大大简化编写自动布局代码的数量。

RIGHT-TO-LEFT LANGUAGE SUPPORT

从右到左的语言支持已经在这儿了!我不知道这是否令人着迷,但显然使用从右到左的语言,例如阿拉伯语的人更期望用户界面右对齐。

RIGHT-TO-LEFT

它的实现是很简单的。他们仅仅使用了“Leading”和“Trailing”的布局属性抽象“Left”和“Right”。在iOS 9之前“Leading”和“Trailing”的布局属性已经存在,但他们相当于“Left”和“Right”。事实上,苹果公司推荐使用“Leading”和“Trailing”来替代“Left”和“Right”。这样你的应用程序支持从右到左的语言只是分分钟的事情!

总结

Auto Layout在iOS 9上做了很多该进,总结下:

  • stack view
  • layout guides
  • layout anchors (fluent interface)
  • right-to-left language support

推荐观看Mysteries of Auto Layout – part 1. 来学习怎样调试Auto Layout问题, 观看Mysteries of Auto Layout – part 2来了解更多细节. 想了解right-to-left language support, 阅读New UIKit Support for International User Interfaces.


本文翻译自WWDC 2015: AUTO LAYOUT IMPROVEMENTS,转载请注明出处。

CocoaPods安装和使用

发表于 2015-09-16

CocoaPods是什么?

当你开发iOS应用时,会经常使用到很多第三方开源类库,比如JSONKit,AFNetWorking等等。可能某个类库又用到其他类库,所以要使用它,必须得另外下载其他类库,而其他类库又用到其他类库。总之,手动一个个去下载所需类库十分麻烦。另外一种常见情况是,你项目中用到的类库有更新,你必须得重新下载新版本,重新加入到项目中,十分麻烦。这个时候,你需要 CocoaPods。

CocoaPods应该是iOS最常用最有名的类库管理工具了,上述两个烦人的问题,通过cocoaPods,只需要一行命令就可以完全解决,当然前提是你必须正确设置它。重要的是,绝大部分有名的开源类库,都支持CocoaPods。所以,作为iOS程序员的我们,掌握CocoaPods的使用是必不可少的基本技能了。

下载和安装

在安装CocoaPods之前,首先要在本地安装好Ruby环境。至于如何在Mac中安装好Ruby环境,请google一下,本文不再涉及。

假如你在本地已经安装好Ruby环境,那么下载和安装CocoaPods将十分简单,只需要一行命令。在终端中输入以下命令:

sudo gem install cocoapods
但是,且慢。如果你在天朝,在终端中敲入这个命令之后,会发现半天没有任何反应。原因无他,因为那堵墙阻挡了cocoapods.org。

但是,是的,又但是(不过是个可喜的“但是”)。我们可以用淘宝的Ruby镜像来访问cocoapods。按照下面的顺序在终端中敲入依次敲入命令:

$ gem sources –remove https://rubygems.org/
//等有反应之后再敲入以下命令
$ gem sources -a http://ruby.taobao.org/
为了验证你的Ruby镜像是并且仅是taobao,可以用以下命令查看:

$ gem sources -l
只有在终端中出现下面文字才表明你上面的命令是成功的:

* CURRENT SOURCES *

http://ruby.taobao.org/
上面所有的命令完成之时,你再次在终端中运行:

$ sudo gem install cocoapods
等上十几秒钟,CocoaPods就可以在你本地下载并且安装好了,不再需要其他设置。

使用

好了,安装好CocoPods之后,接下来就是使用它。所幸,使用CocoPods和安装它一样简单,也是通过一两行命令就可以搞定。

场景1:利用CocoaPods,在项目中导入AFNetworking类库

AFNetworking类库在GitHub地址是:https://github.com/AFNetworking/AFNetworking

为了确定AFNetworking是否支持CocoaPods,可以用CocoaPods的搜索功能验证一下。在终端中输入:

$ pod search AFNetworking

过几秒钟之后,你会在终端中看到关于AFNetworking类库的一些信息。

这说明,AFNetworking是支持CocoaPods,所以我们可以利用CocoaPods将AFNetworking导入你的项目中。

首先,我们需要在我们的项目中加入CocoaPods的支持。先利用Xcode创建一个名字CocoaPodsDemo的项目,用于以下的教程。

你看到这里也许会问,CocoaPods为什么能下载AFNetworking呢,而不是下载其他类库呢?这个问题的答案是,有个文件来控制CocoaPods该下载什么。这个文件就叫做“Podfile”(注意,一定得是这个文件名,而且没有后缀)。你创建一个Podfile文件,然后在里面添加你需要下载的类库,也就是告诉CocoaPods,“某某和某某和某某某,快到碗里来!”。每个项目只需要一个Podfile文件。

好吧,废话少说,我们先创建这个神奇的PodFile。在终端中进入(cd命令)你项目所在目录,然后在当前目录下,利用vim创建Podfile,运行:

$ vim Podfile

然后在Podfile文件中输入以下文字:

platform :ios, '7.0'
pod "AFNetworking", "~> 2.0"

注意,这段文字不是凭空生成的,可以在AFNetworking的github页面找到。这两句文字的意思是,当前AFNetworking支持的iOS最高版本是iOS 7.0, 要下载的AFNetworking版本是2.0。

然后保存退出。vim环境下,保存退出命令是:

:wq
这时候,你会发现你的项目目录中,出现一个名字为Podfile的文件,而且文件内容就是你刚刚输入的内容。注意,Podfile文件应该和你的工程文件.xcodeproj在同一个目录下。

这时候,你就可以利用CocoPods下载AFNetworking类库了。还是在终端中的当前项目目录下,运行以下命令:

$ pod install
因为是在你的项目中导入AFNetworking,这就是为什么这个命令需要你进入你的项目所在目录中运行。

运行上述命令之后,终端出现以下信息:

EricmatoMacBook-Pro:CocoaPodsDemo ericwang$ pod install
Analyzing dependencies
Downloading dependencies
Installing AFNetworking (2.0.2)
Generating Pods project
Integrating client project

[!] From now on use `CocoaPodsDemo.xcworkspace`.

注意最后一句话,意思是:以后打开项目就用 CocoaPodsDemo.xcworkspace 打开,而不是之前的.xcodeproj文件。

你也许会郁闷,为什么会出现.xcodeproj文件呢。这正是你刚刚运行$ pod install命令产生的新文件。除了这个文件,你会发现还多了另外一个文件“Podfile.lock”和一个文件夹“Pods”。 点击 CocoaPodsDemo.xcworkspace 打开之后工程之后,你会惊喜地发现,AFNetwoking已经成功导入项目了。
现在,你就可以开始使用AFNetworking.h啦。可以稍微测试一下,在你的项目任意代码文件中输入:

#import "AFNetworking.h"

然后编译,看看是否出错。

至此,CocoPods的第一个应用场景讲述完毕。过程总结一下就是:

先在项目中创建Podfile,Podfile的内容是你想导入的类库。一般类库的原作者会告诉你导入该类库应该如何写Podfile;
运行命令:`$ pod install.

场景2:如何正确编译运行一个包含CocoPods类库的项目

你也许曾经遇到过(特别是新手iOS开发者)这种情况,好不容易在GitHub上找到一份代码符合自己想需求,兴冲冲下载下来,一编译,傻眼了,发现有各种各样错误。一看,原来是缺失了各种其他第三方类库。这时候莫慌,你再仔细一看,会发现你下载的代码包含了Podfile。没错,这意味着你可以用CocoaPods很方便下载所需要的类库。

下面,以代码 UAAppReviewManager 为例来说明如何正确编译运行一个包含CocoPods类库的项目。

UAAppReviewManager是一个能够让你方便地将提醒用户评分的功能加入你的应用中。当你去UAAppReviewManager的GitHub地址下载这份代码之后,打开Example工程(UAAppReviewManagerExample),编译,你会发现Xcode报告一大堆错误,基本都是说你编译的这份代码找不到某某头文件,这就意味着你要成功编译UAAppReviewManager的Example代码,必须先导入一些第三方类库。同时你会发现在UAAppReviewManagerExample文件夹下面有三个跟CocosPods相关的文件(文件夹):Podfile,Podfile.lock和Pods,这时候,打开终端,进入UAAppReviewManagerExample所在的目录,也就是和Podfile在同一目录下,和场景1一样,输入以下命令(由于已经有Podfile,所以不需要再创建Podfile):

$ pod update

过几秒(也许需要十几秒,取决于你的网络状况)之后,终端出现:

Analyzing dependencies
Fetching podspec for `UAAppReviewManager` from `../`
Downloading dependencies
Installing UAAppReviewManager (0.1.6)
Generating Pods project
Integrating client project

[!] From now on use `UAAppReviewManagerExample.xcworkspace`.

这时候,再回到UAAppReviewManagerExample文件夹看一看,会看到多了一个文件UAAppReviewManagerExample.xcworkspace:

根据终端的信息提示,你以后就需用新产生的UAAppReviewManagerExample.xcworkspace来运行这个Example代码了。

打开UAAppReviewManagerExample.xcworkspace,编译运行,成功!

注意,这里有个小问题,如果刚刚你不是输入$ pod update,而是输入$ pod install,会发现类库导入不成功,并且终端出现下面提示:

[!] Required version (UAAppReviewManager (from `../`)) not found for `UAAppReviewManager`.
Available versions: 0.1.6

这里的意思大概是Podfile文件过期,类库有升级,但是Podfile没有更改。$ pod install只会按照Podfile的要求来请求类库,如果类库版本号有变化,那么将获取失败。但是 $ pod update会更新所有的类库,获取最新版本的类库。而且你会发现,如果用了 $ pod update,再用 $ pod install 就成功了。

那你也许会问,什么时候用 $ pod install,什么时候用 $ pod update 呢,我又不知道类库有没有新版本。好吧,那你每次直接用 $ pod update 算了。或者先用 $ pod install,如果不行,再用 $ pod update。

场景3:使用CocoaPods开发并打包静态库

通常我们用pod来管理第三方开源类库,但我们也极有可能会开发一个用pod管理依赖关系的静态类库给其他人使用,而又不愿意公开源代码,比如一些SDK,那么就需要打包成.a文件。本文将以一个依赖于ASIHTTPRequest的静态类库,来演示如何创建使用了CocoaPods的静态类库以及打包的过程。

开发静态库(Static Library)

创建静态库,有2种方法。

手动创建(deprecated)

过程比较繁琐,纯体力活不推荐,大体步骤说下

  1. 在Xcode中创建一个Cocoa Touch Static Library;
  2. 创建Podfile文件;
  3. 执行pod install完成整个项目的搭建;
    如果需要demo,手动创建示例程序,使用pod添加对私有静态库的依赖,重复执行pod install完成示例项目的搭建。

基于pod自动创建

只需要输入pod的lib命令即可完成初始项目的搭建,下面详细说明具体步骤,以WaterDropView作为项目名演示。

1.执行命令pod lib create WaterDropView。在此期间需要确认下面4个问题。
What language do you want to use?? [ ObjC / Swift ]
> Objc

Would you like to include a demo application with your library? [ Yes / No ]
> Yes

Which testing frameworks will you use? [ Specta / Kiwi / None ]
> None

Would you like to do view based testing? [ Yes / No ]
> No 

What is your class prefix?
> ZM

Running pod install on your new library.

Analyzing dependencies

CocoaPods 0.39.0.beta.4 is available.
To update use: `gem install cocoapods --pre`
[!] This is a test version we'd love you to try.

For more information see http://blog.cocoapods.org
and the CHANGELOG for this version http://git.io/BaH8pQ.

Fetching podspec for `WaterDropView` from `../`
Downloading dependencies
Installing WaterDropView (0.1.0)
Generating Pods project
Integrating client project

[!] Please close any current Xcode sessions and use `WaterDropView.xcworkspace` for this project from now on.

Ace! you're ready to go!
We will start you off by opening your project in Xcode
open 'WaterDropView/Example/WaterDropView.xcworkspace'

To learn more about the template see `https://github.com/CocoaPods/pod-template.git`.
To learn more about creating a new pod, see `http://guides.cocoapods.org/making/making-a-cocoapod`.

第一个问题询问是否提供一个demo项目,通常选择Yes,其他的可以根据需要选择。命令执行完后,就会创建好一个通过cocoapods管理依赖关系的基本类库框架。

2.打开WaterDropView.podspec文件,修改类库配置信息,结果像这样。
#
# Be sure to run `pod lib lint WaterDropView.podspec' to ensure this is a
# valid spec before submitting.
#
# Any lines starting with a # are optional, but their use is encouraged
# To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html
#
Pod::Spec.new do |s|
  s.name             = "WaterDropView"
  s.version          = "0.1.0"
  s.summary          = "A short description of WaterDropView."

# This description is used to generate tags and improve search results.
#   * Think: What does it do? Why did you write it? What is the focus?
#   * Try to keep it short, snappy and to the point.
#   * Write the description between the DESC delimiters below.
#   * Finally, don't worry about the indent, CocoaPods strips it!  
  s.description      = <<-DESC
                   DESC

  s.homepage         = "https://github.com/qcc107/WaterDropView"
  # s.screenshots     = "www.example.com/screenshots_1", "www.example.com/screenshots_2"
  s.license          = 'MIT'
  s.author           = { "qcc107" => "464760435@qq.com" }
  s.source           = { :git => "https://github.com/qcc107/WaterDropView.git", :tag => s.version.to_s }
  # s.social_media_url = 'https://twitter.com/<TWITTER_USERNAME>'

  s.platform     = :ios, '7.0'
  s.requires_arc = true

  s.source_files = 'Pod/Classes/**/*'
  s.resource_bundles = {
  'WaterDropView' => ['Pod/Assets/*.png']
  }

  # s.public_header_files = 'Pod/Classes/**/*.h'
  # s.frameworks = 'UIKit', 'MapKit'
  # s.dependency 'AFNetworking', '~> 2.3'
end

按照默认配置,类库的源文件将位于Pod/Classes文件夹下,资源文件位于Pod/Assets文件夹下,可以修改s.source_files和s.resource_bundles来更换存放目录。s.public_header_files用来指定头文件的搜索位置。
s.frameworks和s.libraries指定依赖的SDK中的framework和类库,需要注意,依赖项不仅要包含你自己类库的依赖,还要包括所有第三方类库的依赖,只有这样当你的类库打包成.a或.framework时才能让其他项目正常使用。

3.进入Example文件夹,执行pod install,让demo项目安装依赖项并更新配置。
$pod install

Analyzing dependencies

CocoaPods 0.39.0.beta.4 is available.
To update use: `gem install cocoapods --pre`
[!] This is a test version we'd love you to try.

For more information see http://blog.cocoapods.org
and the CHANGELOG for this version http://git.io/BaH8pQ.

Fetching podspec for `WaterDropView` from `../`
Downloading dependencies
Using WaterDropView (0.1.0)
Generating Pods project
Integrating client project
4.添加代码。

添加ZMWaterDropView类,注意文件存放的位置在Pod/Classes目录下,跟podspec配置要一致。
运行Pod install,让demo程序加载新建的类。也许你已经发现了,只要新增加类/资源文件或依赖的三方库都需要重新运行Pod install来应用更新。
编写Example代码。

提交本地代码库

1.修改s.source。根据你的实际路径修改。

s.source = { :git => “/Users/name/workspace/ZMWaterDropView”, :tag => ‘0.1.0’ }
2.提交源码,并打tag。

git add .
git commit -a -m ‘v0.1.0’
git tag -a 0.1.0 -m ‘v0.1.0’
验证类库

开发完成静态类库之后,需要运行pod lib lint验证一下类库是否符合pod的要求。可以通过添加–only-errors忽略一些警告。

pod lib lint ZMWaterDropView.podspec –only-errors –verbose
…
ZMWaterDropView passed validation.
打包类库

需要使用一个cocoapods的插件cocoapods-packager来完成类库的打包。当然也可以手动编译打包,但是过程会相当繁琐。

安装打包插件
终端执行以下命令

sudo gem install cocoapods-packager
打包
命令很简单,执行

pod package ZMWaterDropView.podspec –library –force
其中–library指定打包成.a文件,如果不带上将会打包成.framework文件。–force是指强制覆盖。需要特别强调的是,该插件通过对引用的三方库进行重命名很好的解决了类库命名冲突的问题。


本文参考 code4app 和 Bryce Zhang。

阻碍我们成功的八种行为

发表于 2015-09-15   |   分类于 成长中的感悟
你白天黑夜忙个不停,但在事业上却没什么进展。知道吗?可能是你的那些糟糕习惯毁了自己。

来源:网络

有时候,我们会是自己最坏的敌人。我们有意或无意中做的事情会阻挠而不是促进我们成功。排除这些具有破坏性的行为的第一步就是认识它们。以下是最糟糕的八种行为:

1.将忙碌与高效混为一谈

“不要将行动误当作成就。”——约翰·伍登(John Wooden

让我们面对这个问题,你能找到足够多的工作让你白天、黑夜和周末都忙个不停。问题是:这些都是应该做的工作吗?

让你成功的并不是你投入了多少小时或者你同时在干几件事,而是专注于有效果的事情。不要把忙碌和取得进展混淆在一起。我们本应评估那些会对我们的目标产生最大影响的行动所取得的进展,而实际上我们却以忙碌程度作为衡量成功的标准。企业文化或许会对“看上去很忙”进行奖励,但企业真正的成功是在追求长期目标的过程中因专注而取得的成果。

2. 追求完美

“如果你追求完美,你永远都不会满足。”——列夫·托尔斯泰(Leo Tolstoy)

在理想世界中,追求完美不仅高尚,而且会得到回报。在我们生活的这个世界,这是产生挫折感的根源和对时间的巨大浪费。根据心理治疗师梅尔·施瓦兹(Mel Schwartz)的说法:“最接近完美的事物就是能够完全活在当下。没有任何对我们自己进行评估或打分的想法让我们分神,我们自由地活在当下。正是在当下我们才真正活着。然而,完美主义者往往并不活在当下,他们不是忙着批评过去就是反复回想他们的每一个决定或者为他们未来的决定忧心。”

知道什么时候要向前推进,并制定能够取得成果的现实目标。追求完美会让你在前进的道路上停下脚步,或者浪费你原本可以更有成效地用到别处的精力。

3. 避免风险

“没有勇气离开此岸,如何能到达新的彼岸。”——威廉·福克纳(William Faulkner)

除非你是一位金融界的注册风险管理师(CRM),否则完全规避风险的策略无法让你在职业生涯中取得成功。当然,让你像好莱坞特技演员那样接受风险也不是最有效的办法。你必须接受适度的风险,帮助你学习和成长。没有风险,你会在周围的人事业腾飞之际裹足不前。你应该在是否有助于你达成目标的基础上对风险做出评估,然后坚定地追求那些最有机会让你取得进展的目标。

4. 让恐惧阻碍进展

“船舶停在港湾是安全的,但这并不是造船的目的。”——威廉·G.T. 谢特(William G.T. Shedd)

恐惧能阻止你前进的步伐。它造成的破坏会导致停滞。它往往出于疯狂的想象,负面的意象远远超出了现实的情况。如果恐惧阻碍了你的进展,那么你需要从转换心境开始。让恐惧成为帮助你迈出重要第一步的动力,而不要让它将你困在起跑线上。

5. 被动响应与主动规划

“不制订计划就是在计划如何失败。”——阿兰·拉金(Alan Lakein)

成功人士都有计划。他们制订目标、对过程进行规划。他们对成功进行衡量并不时重新校准。如果你发现你每天的大部分工作都是在对其他人的危机做出回应或者回复你收件箱中的任何邮件,那么你是在浪费精力和时间。除非你是在消防部门工作,否则在紧急情况发生后才做出响应,这样的战略不会让你成功。在一堆只会导致你从原定计划上分心的要求把你搞得焦头烂额之际,你有三个工具让自己重回正轨:委派给他人、或礼貌地简短回复,或直接点击“删除”。牢记你的目标。在每天结束时,问问自己你的目标取得了何种进展。

6. 修补弱项

“多年来,我了解到自信的人不会把注意力集中在他们的弱项上——他们最大限度地发挥自己的长处。”——乔伊斯·梅尔(Joyce Meyer)

如果你的演讲了无生趣,到了台上就紧张不安,而你的目标又是成为销售部门的头,那么你需要继续进行演讲,因为它对你的成功至关重要。然而,大多数弱项并不需要你予以注意和弥补。当你花时间“改进”与你的目标没有关联的弱项时,你挤占了可以取得成效的事情所需的时间。把过多时间花在弱项上将导致平庸。如果你把这些时间用在与你目标有关的优势上并最大程度发挥你的长处,你会精通此项技能,脱颖而出并吸引那些能决定你命运的人的注意就不难了。这是让你走上成功之路的最有效方式。避开平庸之处,专注于你的长项。

7. 单干

“如果勇敢无畏,并且保持专注,一个人的力量会很强大,但很多人合作的力量会更强大。”——格洛丽亚·马卡帕加尔·阿罗约(Gloria Macapagal Arroyo)

这对我们中的一些人来说是最大的挑战:认为我们无所不能,靠自己可以搞定一切。这个世界上最多才多艺的人却持不同看法。他们身边围绕着一大群人,他们建立起持续终生的伙伴关系,加入全球最顶级专业人士的团体。如果你单干,你唯一的伴侣将是那些你并不擅长或不喜欢干的事情。

8. 身边围绕着一群与你相似的人

“优势在于差异性,而非相似性。”——史蒂芬·科维(Stephen R. Covey)

身边的人都和你一样而带给你的舒适感受,会产生负面影响。它导致了盲目性,让你通过极为狭隘的视角看待世界。我们都看到过经理人只爱招聘和他们类似的人员,我们身边都有只会说“是”的男同事和女同事。他们让无知指引行动。最成功的领导者会让自己的身边围绕着各种各样的人,这些人挑战他的想法和行动,扩大他的视野并给予他启发,为他带来更加辉煌的成果。

一个水滴动画的实现

发表于 2015-09-14   |   分类于 IT随笔

由于项目需求,最近做了一个水滴落下的加载动画。最简单的实现当然是用UIImageView直接播放,但是考虑到动画的帧数太多,会导致整个应用程序包增大,还有水滴落下和水面碰撞的效果不够随机,最后直接用纯代码实现。

波纹的实现

波浪动画用CAShapeLayer和正弦曲线来模拟,刷新频率为屏幕刷新频率的一半,即30帧每秒。屏幕的刷新用到CADisplayLink,CADisplayLink的精确度优于NSTimer,非常适合这种和屏幕刷新相关的操作。

加载波形层

- (void)loadWaveLayers{

if (!_waveLayers) 
{
    self.waveLayers = [[NSMutableArray alloc] initWithCapacity:3];

    UIColor *whiteColor = [UIColor whiteColor];
    UIColor *lightGrayColor = [UIColor colorWithRed:207/255.0f
                                              green:207/255.0f
                                               blue:207/255.0f
                                              alpha:1.0f];
    UIColor *darkGrayColor = [UIColor colorWithRed:159/255.0f
                                             green:159/255.0f
                                              blue:159/255.0f
                                             alpha:1.0f];

    NSArray *colors = @[darkGrayColor, lightGrayColor, whiteColor];

    for (int i = 0; i < 3; ++i) {
        CAShapeLayer *waveLayer = [CAShapeLayer layer];
        waveLayer.fillColor = ((UIColor *)colors[i]).CGColor;
        [self.layer addSublayer:waveLayer];

        [_waveLayers addObject:waveLayer];
    }
}
}

设置定时器

_frameTimer = [CADisplayLink displayLinkWithTarget:self selector:@selector(updateVibrations:)];
_frameTimer.frameInterval = 2;
[_frameTimer addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSRunLoopCommonModes];

更新数值

- (void)updateVibrations:(CADisplayLink *)displayLink
{
if (_increase) {
    _variable += 1 / 30.0f;
}else{
    _variable -= 1 / 30.0f;
}

if (_variable <= 1) {
    _increase = YES;
}

if (_variable >= 1.6) {
    _increase = NO;
}

_offsetX += _waveSpeed;

[self drawWaveWithLayer:_waveLayers[0] amplitude:_variable * 3 waveCycle:1.5* M_PI / _waveWidth offsetY:20.0f];    // dark
[self drawWaveWithLayer:_waveLayers[1] amplitude:_variable * 5 waveCycle:1.1 * M_PI / _waveWidth offsetY:22.0f];   // light
[self drawWaveWithLayer:_waveLayers[2] amplitude:_variable * 10 waveCycle:1 * M_PI / _waveWidth offsetY:22.0f];    // white
}

绘制正弦曲线

 - (void)drawWaveWithLayer:(CAShapeLayer *)waveLayer
           amplitude:(CGFloat)amplitude
           waveCycle:(CGFloat)waveCycle
             offsetY:(CGFloat)offsetY
{
   CGMutablePathRef path = CGPathCreateMutable();
   CGFloat y = self.bounds.size.height * 0.5f;
   CGPathMoveToPoint(path, nil, 0, y);

   for (float x = 0.0f; x <=  _waveWidth ; x++) {
       y = amplitude * sin(waveCycle * x + _offsetX) + self.frame.size.height * 0.5f + offsetY;   // 正弦波
       CGPathAddLineToPoint(path, nil, x, y);
   }

   CGPathAddLineToPoint(path, nil, _waveWidth, self.frame.size.height);
   CGPathAddLineToPoint(path, nil, 0, self.frame.size.height);
   CGPathCloseSubpath(path);

   waveLayer.path = path;
   CGPathRelease(path);
}

绘制水滴

绘制水滴的视图

自定义一个View继承自UIView,在drawRect中实现:

- (void)drawRect:(CGRect)rect {
// Drawing code

CGContextRef context = UIGraphicsGetCurrentContext();

CGContextMoveToPoint(context, self.bounds.size.width * 0.5f, 0);

[[UIColor whiteColor] set];
CGContextSetLineWidth(context, 1.0);

CGContextAddCurveToPoint(context,
                         0,
                         self.bounds.size.height,
                         self.bounds.size.width,
                         self.bounds.size.height,
                         self.bounds.size.width * 0.5f,
                         0);

CGContextSetFillColorWithColor(context,[UIColor whiteColor].CGColor);
CGContextFillPath(context);

CGContextStrokePath(context);
}

这里要保证水滴视图的宽高比为2:1,这样贝塞尔曲线绘制出来的才是水滴形状。

给水滴添加重力和碰撞检测

这里用到了UIKit动力学。

UIGravityBehavior *gravityBeahvior = [[UIGravityBehavior alloc] initWithItems:@[_dripView]];
[_animator addBehavior:gravityBeahvior];

UICollisionBehavior *collisionBehavior = [[UICollisionBehavior alloc] initWithItems:@[_dripView]];
collisionBehavior.translatesReferenceBoundsIntoBoundary = NO;

CGPoint rightEdge = CGPointMake(_barrierLine.frame.origin.x + _barrierLine.frame.size.width,
                                _barrierLine.frame.origin.y);

[collisionBehavior addBoundaryWithIdentifier:@"barrier"
                            fromPoint:_barrierLine.frame.origin
                              toPoint:rightEdge];
collisionBehavior.collisionDelegate = (id)self;
[_animator addBehavior:collisionBehavior];


UIDynamicItemBehavior *itemBehaviour = [[UIDynamicItemBehavior alloc] initWithItems:@[_dripView, _barrierLine]];
itemBehaviour.elasticity = 0.0;
[_animator addBehavior:itemBehaviour];

水滴和波浪碰撞后的喷溅效果

创建圆形水珠

- (void)splashWater
{
if (!_dripLayers) {
    _dripLayers = [[NSMutableArray alloc] initWithCapacity:kDripCount];

    for (int i = 0; i < kDripCount; i++) {

        CALayer *dripLayer = [CALayer layer];
        [_dripLayers addObject:dripLayer];

    }
}

for (int i = 0; i < kDripCount; i++) {

    [self performSelector:@selector(addAnimationToDrip:) withObject:_dripLayers[i] afterDelay:i * 0.01];
}
}

给水珠添加抛物线动画

- (void)addAnimationToDrip:(CALayer *)dripLayer
{
CGFloat width = arc4random() % 15 + 1;
dripLayer.frame = CGRectMake((self.bounds.size.width - width)* 0.5f, self.bounds.size.height * 0.5f + 40, width, width);
dripLayer.cornerRadius = dripLayer.frame.size.width * 0.5f;
dripLayer.backgroundColor = [UIColor whiteColor].CGColor;

[self.layer addSublayer:dripLayer];

CGFloat x3 = arc4random() % ((int)self.bounds.size.width) + 1;
CGFloat y3 = self.bounds.size.height * 0.5f + 40;

CGFloat height = arc4random() % ((int)(self.bounds.size.height * 0.5f));

[self throwDrip:dripLayer
           from:dripLayer.position
             to:CGPointMake(x3, y3)
         height:height
       duration:0.7f];
 }


 - (void)throwDrip:(CALayer *)drip
         from:(CGPoint)start
           to:(CGPoint)end
       height:(CGFloat)height
     duration:(CGFloat)duration
{

CGMutablePathRef path = CGPathCreateMutable();

CGPathMoveToPoint(path, NULL, start.x, start.y);
CGPathAddQuadCurveToPoint(path, NULL, (end.x + start.x) * 0.5f, -height, end.x, end.y);

CAKeyframeAnimation *animation = [CAKeyframeAnimation animationWithKeyPath:@"position"];
[animation setPath:path];
animation.duration = duration;
CFRelease(path);
path = nil;Demotic

[drip addAnimation:animation forKey:@"position"];
}

项目地址

WaterDropDemo

1234
翻盖的乌龟

翻盖的乌龟

沙滩一躺三年半,大浪来时我翻身。

19 日志
3 分类
© 2019 翻盖的乌龟
由 Hexo 强力驱动
主题 - NexT.Mist