敏捷实践系列(五):迁移已有项目到Git flow

上一篇 敏捷实践系列(四):代码管理流程 给大家详细的讲解了一下Git flow, 本周我们就把一个客户的所有项目实施了Git flow, 如果说你详细看了那篇文章,那么你就能了解为何要进行Git flow 以及如何对一个新项目按Git flow的流程操作, 但是当我们整理已有的项目时,我们发现了以下几个问题需要一些方法处理。

错乱的分支名如何解决

问题

我们遇到的一个项目,一开始生产环境用的是master分支,突然客户提出他们有一个客户有特殊需求,让打一个分支出来,团队成员就打出了一个master-quickfix 分支,但是后来这个分支上功能越来越多,慢慢的团队成员就把这个分支当做master分支用了,此时develop和 master-quickfix 分支也早已分道扬镳。然后所有的客户又需要相同的功能,这样如果想合并会master将是非常难的,因为冲突太大。 经过沟通和核实,我们发现现在的master-quickfix其实承担了master的角色,所以我们要让master-quickfix当做master.

方案

方案一 用master-quickfix 代码覆盖master

git checkout master-quickfix

merge master - ignoring master's changes
git merge -s ours master

git checkout master

# finally merge all our stuff to new master - actually it replaces the master with master-quickfix
git merge master-quickfix

# now master-quickfix can be deleted
git push origin: master-quickfix

然后我们就看到master上代码已经和原来master-quickfix上一样了,但是这个方法有一个问题就是 master-quickfix上的提交日志没有了,如果你不在乎提交日志那么就可以使用这个方法。

方案二 改分支名

git branch -m master new_master         # Rename branch locally    
git push origin :master                 # Delete the old branch    
git push --set-upstream origin new_master   # Push the new branch, set local branch to track the new remote


git branch -m master-quickfix master         # Rename branch locally    
git push origin : master-quickfix                 # Delete the old branch    
git push --set-upstream origin master   # Push the new branch, set local branch to track the new remote

使用这个方法,就可以看到master-quickfix上的分支的提交记录,过程当中会删除旧的远程master分支,以及master-quickfix分支
,所以需要你确认要删除的分支有备份及没有问题,危险系数5星, 我在做这个操作的时候向别人确认了多次。我操作的时候手都抖呀!

不同的客户不同的分支问题

问题

原来有一个项目,项目有不同的客户,导致不同的客户的代码在不同的分支上,这导致代码难以管理,功能散乱在各个分支,时间久了,开发人员都不知道每个分支上有哪些功能。

解决方案

针对这个问题,我们的想法是不同客户使用同一套代码库,还是使用Git flow, 因为不同的客户需要不同的功能,这其实就是一个SaaS系统,所以我们把系统改为SaaS系统,代码用同一套,不同的客户使用什么功能使用SaaS管理端来配置。 这样做有很多好处,比如:给A客户做的功能很容易再卖给B客户,同时很容易给不同的客户做个性化的配置,例如界面样式等等。 当然,这个需要你的强大的沟通能力,因为改为SaaS需要时间哪,时间就是金钱嘛!

如果你的客户不同意,或者你需要项目遵守一些”特殊规则或者某个国家特殊政策”,导致整套系统非常不同, 那么我的建议是你重新建一个代码库给这个特殊客户,而不要用分支来区分。

总结

由于我们团队的敏捷程度还可以,所以推行Git flow的流程除了以上几个技术上的问题以外,其它的都很顺利。 如果你想实行Git flow,那么再次提醒务必完全理解这个流程再开始。请阅读:敏捷实践系列(四):代码管理流程

  

敏捷实践系列(四):代码管理流程

本来没有这么快到流程以及技术部分,但是因为公司需要,所以就临时写了这一部分。

我们已经从SVN 切换到Git很多年了,现在几乎所有的项目都在使用Github管理。对与那些还在坚持使用SVN的,我实在想不出原因,权且称作守旧派吧。

Git的优点

Git的优点很多,但是这里只列出我认为非常突出的几点。

  1. 由于是分布式,所有本地库包含了远程库的所有内容。
  2. 优秀的分支模型,打分支以及合并分支,机器方便。
  3. 快速,在这个时间就是金钱的时代,Git由于代码都在本地,打分支和合并分支机器快速,使用个SVN的能深刻体会到这种优势。

感兴趣的,可以去看一下Git本身的设计,内在的架构体现了很多的优势,不愧是出资天才程序员Linus (Linux之父) 之手

版本管理的挑战

虽然有这么优秀的版本管理工具,但是我们面对版本管理的时候,依然有非常大得挑战,我们都知道大家工作在同一个仓库上,那么彼此的代码协作必然带来很多问题和挑战,如下:

  1. 如何开始一个Feature的开发,而不影响别的Feature?
  2. 由于很容易创建新分支,分支多了如何管理,时间久了,如何知道每个分支是干什么的?
  3. 哪些分支已经合并回了主干?
  4. 如何进行Release的管理?开始一个Release的时候如何冻结Feature, 如何在Prepare Release的时候,开发人员可以继续开发新的功能?
  5. 线上代码出Bug了,如何快速修复?而且修复的代码要包含到开发人员的分支以及下一个Release?

大部分开发人员现在使用Git就只是用三个甚至两个分支,一个是Master, 一个是Develop, 还有一个是基于Develop打得各种分支。这个在小项目规模的时候还勉强可以支撑,因为很多人做项目就只有一个Release, 但是人员一多,而且项目周期一长就会出现各种问题。

Git Flow

就像代码需要代码规范一样,代码管理同样需要一个清晰的流程和规范

Vincent Driessen 同学为了解决这个问题提出了 A Successful Git Branching Model

下面是Git Flow的流程图

上面的图你理解不了? 没关系,这不是你的错,我觉得这张图本身有点问题,这张图应该左转90度,大家应该就很用以理解了。

Git Flow常用的分支

  • Production 分支

也就是我们经常使用的Master分支,这个分支最近发布到生产环境的代码,最近发布的Release, 这个分支只能从其他分支合并,不能在这个分支直接修改

  • Develop 分支

这个分支是我们是我们的主开发分支,包含所有要发布到下一个Release的代码,这个主要合并与其他分支,比如Feature分支

  • Feature 分支

这个分支主要是用来开发一个新的功能,一旦开发完成,我们合并回Develop分支进入下一个Release

  • Release分支

当你需要一个发布一个新Release的时候,我们基于Develop分支创建一个Release分支,完成Release后,我们合并到Master和Develop分支

  • Hotfix分支

当我们在Production发现新的Bug时候,我们需要创建一个Hotfix, 完成Hotfix后,我们合并回Master和Develop分支,所以Hotfix的改动会进入下一个Release

Git Flow如何工作

初始分支

所有在Master分支上的Commit应该Tag

Feature 分支

分支名 feature/*

Feature分支做完后,必须合并回Develop分支, 合并完分支后一般会删点这个Feature分支,但是我们也可以保留

Release分支

分支名 release/*

Release分支基于Develop分支创建,打完Release分之后,我们可以在这个Release分支上测试,修改Bug等。同时,其它开发人员可以基于开发新的Feature (记住:一旦打了Release分支之后不要从Develop分支上合并新的改动到Release分支)

发布Release分支时,合并Release到Master和Develop, 同时在Master分支上打个Tag记住Release版本号,然后可以删除Release分支了。

维护分支 Hotfix

分支名 hotfix/*

hotfix分支基于Master分支创建,开发完后需要合并回Master和Develop分支,同时在Master上打一个tag

Git Flow代码示例

a. 创建develop分支

git branch develop
git push -u origin develop

b. 开始新Feature开发

git checkout -b some-feature develop

# Optionally, push branch to origin:
git push -u origin some-feature



# 做一些改动


git status
git add some-file
git commit

c. 完成Feature

git pull origin develop
git checkout develop
git merge --no-ff some-feature
git push origin develop

git branch -d some-feature

# If you pushed branch to origin:
git push origin --delete some-feature

d. 开始Relase

git checkout -b release-0.1.0 develop

# Optional: Bump version number, commit
# Prepare release, commit

e. 完成Release

git checkout master
git merge --no-ff release-0.1.0
git push

git checkout develop
git merge --no-ff release-0.1.0
git push

git branch -d release-0.1.0

# If you pushed branch to origin:
git push origin --delete release-0.1.0




git tag -a v0.1.0 master
git push --tags

f. 开始Hotfix

git checkout -b hotfix-0.1.1 master

g. 完成Hotfix

git checkout master
git merge --no-ff hotfix-0.1.1
git push




git checkout develop
git merge --no-ff hotfix-0.1.1
git push

git branch -d hotfix-0.1.1

git tag -a v0.1.1 master
git push --tags

Git flow工具

实际上,当你理解了上面的流程后,你完全不用使用工具,但是实际上我们大部分人很多命令就是记不住呀,流程就是记不住呀,肿么办呢?

总有聪明的人创造好的工具给大家用, 那就是Git flow script.

安装

  • OS X

brew install git-flow

  • Linux

apt-get install git-flow

  • Windows

wget -q -O - –no-check-certificate https://github.com/nvie/gitflow/raw/develop/contrib/gitflow-installer.sh | bash

使用

  • 初始化: git flow init

  • 开始新Feature: git flow feature start MYFEATURE

  • Publish一个Feature(也就是push到远程): git flow feature publish MYFEATURE

  • 获取Publish的Feature: git flow feature pull origin MYFEATURE

  • 完成一个Feature: git flow feature finish MYFEATURE

  • 开始一个Release: git flow release start RELEASE [BASE]

  • Publish一个Release: git flow release publish RELEASE

  • 发布Release: git flow release finish RELEASE
    别忘了git push –tags

  • 开始一个Hotfix: git flow hotfix start VERSION [BASENAME]

  • 发布一个Hotfix: git flow hotfix finish VERSION

Git Flow GUI

上面讲了这么多,我知道还有人记不住,那么又有人做出了GUI 工具,你只需要点击下一步就行,工具帮你干这些事!!!

SourceTree

当你用Git-flow初始化后,基本上你只需要点击git flow菜单选择start feature, release或者hotfix, 做完后再次选择git flow菜单,点击Done Action. 我勒个去,我实在想不到还有比这更简单的了。

目前SourceTree支持Mac, Windows, Linux.

这么好的工具请问多少钱呢? 免费!!!!

Git flow for visual studio

广大VS的福音
GitFlow for Visual Studio

  

敏捷实践系列(三):沟通

大话西游里有一段因为没有沟通的经典, 结局如何大家都知道。

唐僧:你想要啊?悟空,你要是想要的话你就说话嘛,你不说我怎么知道你想要呢,虽然你很有诚意地看着我,可是你还是要跟我说你想要的。你真的想要吗?那你就拿去吧!你不是真的想要吧?难道你真的想要吗?……

悟空:…

敏捷项目沟通尤其重要

敏捷开发多采用短迭代,要求尽快交付可以工作的软件,所以项目的需求文档就很难像原来的瀑布开发模式一样面面俱到。这就要求我们多进行沟通以确保双方的理解一致。根据以往很多项目的经验来看,失败的项目很多都是缺乏沟通,成功的项目必然是沟通做的比较好的。

敏捷经常出现的沟通问题

你以为你以为的就是你以为的

有时候,我们很多人做项目,拿到项目的需求以后,自己简单看了看,然后就开始做了,等到我们做完一个迭代以后,拿给客户看时,完全不是客户要的东西,因为我们对项目的需求的理解比较片面,就是自以为是。

不敢沟通

还有的人,尤其是新入团队的人,客户写的东西或者说的东西,自己没有完全理解,然后又不问,他总觉客户已经说过了,已经写过了,然后再去问客户,是不是不妥?如果按自己的理解或者猜测万一对了呢?, 然后就碰运气。 事实上我们的猜测都常常都是错误的,尤其是在我们对项目没有更全局的了解的情况下。

拖延

还有一类沟通的问题,就是我们自己也发现了问题,需求上的,或者客户的流程上的,但是我们总是心想等到明天沟通,明天再等明天,其实是希望这个问题自动消失,但最终的结果往往越来越严重。

不敢沟通客户的问题

在我的一些项目里,比如我们团队觉得客户那边需要提高,比如需求都很碎片化,客户的UI改来改去,希望客户能提供一个比较接近Final Design的设计,但是总觉得说出客户的问题不好意思,或者对客户的不尊重,实际上我们提出问题和自己的想法才是对客户最大的尊重。

沟通方法单一

我们很多人习惯了一种沟通方式,不管什么问题都是同一种,所有的问题都写邮件或者所有的问题都用语音,这也是很没沟通效率的方式。

敏捷项目如何沟通

平等沟通的意识

首先,我们要理解,敏捷项目里的沟通,不管是与客户还是与团队成员,大家都是平等的,沟通项目相关的问题都是平等的,尤其是把客户也当做自己团队的一部分,客户也是希望项目做好的那一个人, 只有这样,我们才能畅所欲言,无所顾忌,更不会有想法掖着藏着。

多种沟通方式结合

小平说: “白猫黑猫,抓住老鼠就是好猫”,沟通也一样,下面是常见的几种沟通方式。

  • 面对面
  • 视频
  • 语音
  • IM 文字沟通
  • 邮件沟通

这几种沟通方式的效率一般情况下由高到低,所以我们尽量选择沟通效率比较高的方式, 因为当我们能看见对方的时候,我们可以根据对方的表情就可以看出来对方是否真的理解了自己所说的。

但是实际当中我们需要多种沟通方式的有效结合,比如离岸团队面对面的机会比较少,我们可以视频和语音,但是视频语音由于他强调及时性,需要大家的时间都合适,但是视频语音也有缺点,很难有文字记录,虽然可以录音,但是视频和语音很难搜索内容,也较难在组内传播。 那么文字沟通有时候就体现出了很多的优势,有历史记录,多人可以参与等。

但是IM得文字沟通也有一些不足,比如很难通过图形沟通,对图形标注等,除此之外,很多时候很难及时给出答案等,那么邮件的优势就是不需要客户立即回复,也给客户更多的时间思考,同时格式化的文档更容易把一件事情描述清楚。

所以,我们在沟通的时候,要结合情况选择最适合,最快速能够把问题沟通清楚的方式。

一图胜千言

软件项目很多时候,图形化的沟通非常重要,我们很多项目的设计,以及架构,开发人员难以达到统一的认识,就是缺乏图形,设计图或者架构图。我们都知道,人对图形的记忆力要好于文字。

系统之间的交互,软件如何部署,项目的架构封层等,这些用图形来表示往往一页纸就可以,而且大家看后,很容易理解,很容易记住。因为只有别人对你的想法理解了,别人才能够发现你的问题,才能给出建议。我觉得软件项目,非常重要的两张图,一个是 Architecture Diagram, 一个是Use Case Diagram, 这两张图可以大大节省项目的开发沟通时间。

原型或者草图

敏捷项目流行边做边改,但是我对这个是不太认可的,客户付钱是让我们把事情做对而不是把事情改对。那么怎么样能够在做之前尽量就明白要做什么?那就是先做一个原型,我说的原型是不需要花太多时间的,如果花太多时间就得不偿失了,比如UI我们可以先在开发之前先画出Wireframe, 如果需要交互,我们可以先做交互的Prototype. 现在有很多工具比如Invision都可以建立静态图形之间的交互,这样可以大大减少返工的时间。

提出问题时尽量给出方案

很多人只问问题,所以导致客户回复的很慢,因为客户需要思考,但是有的时候客户思考后给我们的方案又不适合,所以一来二去就浪费了很多时间,那么好的方法是就是,我们给客户提的问题,想想是不是我们没有方案呢? 还是我们有多个方案不能确定是哪一个方案呢?很多时候我们其实有方案的。

我们都知道我们上学的时候都喜欢做判断题,其次是选择题,其次是填空,最不想做的就是问答题,想想我们要想得到客户的快速反馈,我们是不是想想应该给客户出比较容易做的题呢?

其实,凡是我们提的方案被客户采纳的,我们做起来也更顺手,也就更有效率。

总结

最后,沟通最主要的两点:

  1. 如果你想要,就一定要说,不说,别人怎么知道你想要呢? (敢于沟通)
  2. 要想尽一切办法, 让客户觉得:“你以为你以为的就是你以为的” (确认自己的想法)
  

敏捷实践系列(二):敏捷意识

上篇文章我提到了敏捷的心法,但是我想除了心法之外,更重要的是敏捷的意识。

为什么意识更重要?

意识:辩证唯物主义的解释是,意识是物质运动变化的场所,意识是人脑对大脑内外表象的觉察,即它可以辨识自己脑区中的表象是来自于外部感官的还是来自于想像或回忆的。

我们这里说的意识,一是你能主管的去想一件事情,另一个就是你对一件事情的发自内心的认可程度。

敏捷,光有心法是没有用的,有没有要敏捷的意识,敏捷的意愿。有没有主观的愿望去做,我们经常说的话:没有成不成,就是看你想不想做。

欲推敏捷,首先要培养敏捷的意识

我举两个例子:

一个是最近推行**”无车日”**, 无车日本来是想让大家绿色出行,减少二氧化碳的排放,但是结果是什么,结果是堵的一塌糊涂。 为什么?据说原因如下:有车的人想,本来平时不开车,但是今天无车日,路上车少,那我就开车肯定不赌。这样造成的结果是,坐公交的人觉得无车日大家都挤公交,开车的人觉得今天无车日开车应该不赌,所以开车。造成的结果是,公交也堵,开车也堵。这就是政府和民众对环保的意识不够,如果政府意识够了,那么政府是不是多提供公共交通的数量,以及提高公共交通的便捷以及服务?如果民众意识够了,那么我是不是可以走着去上班?我是不是可以骑自行车?我是不是可以跑步?若能如此,无车日才有了真正的意义。

另一个例子,就是我看到的道路旁边的自行车道栅栏,政府甚至花了不少钱来弄这个,但是效果呢? 我看到的情况是很多地方没人用,甚至造成地段的拥堵。为什么? 有些地方自行车道里面有面包车在里面堵着,还有的地方有人逆向骑过来,试想,如果你骑自行车有这样的经历,你还会骑自行车道吗?骑到中间你飞出来? 如果这个自行车道没人用,那么另一个问题又来,本来3车道,现在一个车道停车,一个车道过车,原来没有自行车道时,如果前面的车临时停车,其他的人还能利用空的地方错开车,现在就能硬等,这样岂不是更堵?结果就是,本来就赌的路,硬硬的把路切一块空着浪费了!

从上面的两个例子,我们都能感觉到,都是为了要把事情做好,但是,就是意识层面没做好工作,才导致截然相反的结果。(以上只是我自己片面的感觉,真正的事实数据请看官方数据)。

如何培养敏捷的意识?

首先,我觉得培养敏捷的意识之前,首先要知道是什么事敏捷的意识,我觉得敏捷的意识就是:

  • 高质、高效的做事情
  • 持续的学习
  • 团队精神,Good team player.
  • 责任心
  • 关心客户的价值
  • 解决问题
  • 努力改变现状,不抱怨现状。

其次,那么如何培养敏捷的意识呢?我个人觉得两种方式:

  • 招聘具有敏捷意识的人。 其实我列的敏捷的意识和大家想象的SCRUM那些无关的。

  • 培养已有的人具有上面提到的敏捷的意识,方法比如说是宣传、强调、加薪、惩罚等等各种方法,关键是推行的人自己有没有这个意识来推行敏捷。

最后,最重要的是要让大家知道为什么要敏捷,敏捷解决的问题是什么?敏捷对工程师自己的好处是什么?因为只有人敏捷了,项目才能敏捷,所有的项目都敏捷了,公司才能说是一个敏捷的公司。若如此,强行推行一个SCRUM框架,持续交付等等,就必然走向文章开头的那两个例子,结果只能是适得其反。

愿君更饮一杯酒,敏捷路上无故人。

且行、且思、切记!

(注:佛光,图片拍摄于2015-6-6 太白山)
  

敏捷实践系列(一):什么是敏捷

开篇:

悟空:师傅,为什么你写东西,喜欢写系列呢?
师傅:因为很多东西需要长期的实践呀。
悟空:怎么又开始说敏捷了
师傅:就像一本好书,常读常新,人生不同阶段过的都是不同的人生呀。
悟空:师傅,为什么你原来用上、中、下呢?
师傅:因为原来只写了个上中,别人一直问下,现在如果只写一二,别人要问,我就说写完了呀!
悟空:。。。。。。

敏捷是什么?

其实别人问敏捷是什么?几年前我觉得很好回答,但是现在我觉得很难回答,就像你问天龙八部里的扫地僧:“功夫是什么?” 我觉得他可能真的会被问住的。你再问:功夫是“降龙十八掌”?, 是“九阴真经”?,是“一阳指”?他可能说不是,但是待会儿他可能会说:“也算”。

所以很多人问我什么是敏捷,我其实很难定义,用了SCRUM算吗?用了Kanban算吗?用了Target Process,Trello算吗?我也只能说:“也算,也不算”。

还有人觉得用了持续集成,用了测试驱动开发,用了结对这个应该算是敏捷了吧? 我只能说如果你用了“轩辕剑”,“倚天剑”,“屠龙刀”,”莫问剑”,”游龙剑”,你就是高手吗?君不见,扫地僧一把扫帚就制服两大高手? 由此我们可以看到功夫要好,更重要的是内功,是心法。

敏捷的心法是什么?

这个心法其实就是武林高手总结的敏捷宣言

  • 个体和交互 胜过 过程和工具

  • 可以工作的软件 胜过 面面俱到的文档

  • 客户合作 胜过 合同谈判

  • 响应变化 胜过 遵循计划

这个其实就是:“九阴真经”,“易筋经”,“六脉神剑”,“葵花宝典”(正宗的是不需要自宫的)

知道了心法,其实每个人的修炼方法都不一样,但是前人为了后人节省时间,给出了自己修炼的一些经验和原则,那就是十二条原则。

  1. 最优先的目标是通过尽早地、持续地交付有价值的软件来满足客户

  2. 欢迎需求变化,甚至在开发后期。敏捷过程控制、利用变化帮助客户取得竞争优势

  3. 频繁交付可用的软件,间隔从两周到两个月,偏爱更短的时间尺度

  4. 在整个项目中业务人员和开发人员必须每天在一起工作

  5. 以积极主动的员工为核心建立项目,给予他们所需的环境和支持,信任他们能够完成工作

  6. 在开发团队内外传递信息最有效率和效果的方法是面对面的交流

  7. 可用的软件是进展的主要度量指标

  8. 敏捷过程提倡可持续发展。发起人、开发者和用户应始终保持稳定的步调

  9. 持续关注技术上的精益求精和良好的设计以增强敏捷性

  10. 简化——使必要的工作最小化的艺术——是关键

  11. 最好的架构、需求和设计产生于自我组织的团队

  12. 团队定期地对运作如何更加有效进行反思,并相应地调整、校正自己的行为

注意:上面我说的是这是前人根据自己修炼的过程总结出来的经验,那么也就是说只是经验,100%可以拿来自己用?那就不一定。

比如有一条原则说:情人节一定要给老婆买花?那么问题来了,没老婆怎么办? 当然是先找个老婆。总不能买花送给别人老婆吧。

比如,上面有一条:“在整个项目中业务人员和开发人员必须每天在一起工作”, 很多时候很难,那么怎么办?第一创造条件能让业务和开发人员每天在一起工作,这个一起不一定是坐在一起,可以每天及时回复你的邮件,也可以你自己就当业务人员,那么你自己不就是每天和自己在一起?

怎么样才算敏捷了?

尽管公司实行敏捷也很多年了,这个问题,我想说我不知道怎么回答,因为我们也还在努力变得更敏捷,但是我理想中的敏捷,应该是这样子的:“草在发它的牙,风在摇它的叶,小鸟在唱他的歌,而敏捷团队的Leader静静的座在那里一句话也不用说”,此时敏捷就像空气一样充满了整个房间,知道有一天PM高了,这个时候大家说:“哎呦,最近是不是不敏捷了?”

怎么开始敏捷呢?

重要的事情说三遍:

  • 读书,实践!
  • 读书,实践!
  • 读书,实践!
  

iOS UI系列 (四) :可复用的Xib(1) 静态内容

有时候页面中的部分内容相同,或者是一些静态的内容组合,这时候我们就可以把这些见面封装到一个XIB里

新建Single View Application

新建一个View.Xib

  1. Command+N–>User Interface–>View
  2. 把界面大小改为Freeform
  3. 添加一个UILabel, 两个UIView, 并设置对应的背景色
  4. 添加对应的约束,让两个UIView等宽,且Space都是10, 高度固定,且与周围的约速为10, 对UILabel也设置对应的约速,细节就不写了,看图

使用Xib

在ViewController添加 一个UIView, 并设置对应的约束,连接这个UIView为Controller的 IBOutlet ContainerView

  1. 在ViewDidLoad里添加如下代码
1
2
3
4
5
6
7
super.viewDidLoad()

let arr = NSBundle.mainBundle().loadNibNamed("View", owner: nil, options: nil)

let v = arr[0] as! UIView

containerView.addSubview(v)

运行

  1. 添加约束
1
2
3
4
5
6
7
8
9
10
11
12
13
14
import UIKit

class ViewController: UIViewController {

@IBOutlet weak var containerView: UIView!

var v: UIView!

override func viewDidLoad() {

super.viewDidLoad()

let arr = NSBundle.mainBundle().loadNibNamed("View", owner: nil, options: nil)
v = arr[0] as! UIView


​ containerView.addSubview(v)

1
setUpConstraint()


​ // Do any additional setup after loading the view, typically from a nib.
​ }

1
2
3
4
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}


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
 func setUpConstraint()
{

v.setTranslatesAutoresizingMaskIntoConstraints(false)

containerView.addConstraint(NSLayoutConstraint(
item:v, attribute:.Leading,
relatedBy:.Equal, toItem:containerView,
attribute:.Left, multiplier:1, constant:0))

containerView.addConstraint(NSLayoutConstraint(
item:v, attribute:.Trailing,
relatedBy:.Equal, toItem:containerView,
attribute:.Right, multiplier:1, constant:0))

containerView.addConstraint(NSLayoutConstraint(
item:v, attribute:.Top,
relatedBy:.Equal, toItem:containerView,
attribute:.Top, multiplier:1, constant:0))

containerView.addConstraint(NSLayoutConstraint(
item:v, attribute:.Bottom,
relatedBy:.Equal, toItem:containerView,
attribute:.Bottom, multiplier:1, constant:0))

}

}


3. 运行结果, 我们的Xib已经可以自适应容器了


iOS UI系列 (三) :Reusable Button

有时候我们需要给一些做一些设置,但是这些控件却需要用在多个地方,如果在每一个ViewController都设置一遍,那么代码就不整洁了,而且比较耗时间。

创建一个RoundButton.swift 文件,集成自UIButton

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
import UIKit

class RoundButton: UIButton {

/*
// Only override drawRect: if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
override func drawRect(rect: CGRect) {
// Drawing code
}
*/

required init(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}

override init(frame: CGRect) {
super.init(frame: frame)
}

override func awakeFromNib() {

self.layer.cornerRadius=10
self.layer.borderColor=UIColor.redColor().CGColor
self.layer.borderWidth=2
self.layer.backgroundColor=UIColor.yellowColor().CGColor
self.contentEdgeInsets=UIEdgeInsets(top: 10,left: 10,bottom: 10,right: 10)
}
}




设置UIButton的Custom class为 RoundButton

iOS UI系列 (二) :使用多个StoryBoard

为什么要使用多个StoryBoard

StoryBoard 给项目带了很大的方便,在一个视图里可以看到整个项目页面之间的关系,但是如果项目所有的页面都放到一个StoryBoard, 会带来以下一些问题

  • UIStoryBoard太大
  • 每次打开StoryBoard比较慢
  • 一个窗口里面显示所有的View,显得比较混乱,尤其是一个显示器看不全的时候
  • UIStoryBoard 项目解决源码冲突太麻烦

所以,我建议项目使用多个StoryBoard, 不同模块使用不同的UIStoryBoard, 下面是如何使用的实例。

Main Storyboard

首先建立一个Single View Application, 在StoryBoard里添加2个UIViewController, 并且设置好导航关系

新建一个SecondViewController类, Command+N–>Coca Touch cass–>Next, 继承UIViewController, 选择Swift语言

import UIKit

class SecondViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()

        // Do any additional setup after loading the view.
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }
}

设置第二ViewController的File’s owner 的class为刚新建的SecondViewController

第二个StoryBoard

Command+N–>User Interface—>StoryBoard,命名Second

添加2个UIViewController, 并添加对应的按钮,将View的背景色改为黄色,以区别这是第二个UIStoryBoard, 按住Ctrl从第一个ViewController拖到第二个ViewController,选择Show

设置第一个UIViewController如下

<img class=”img-responsive”src=”https://cdn.jsdelivr.net/gh/wangdeshui/blogpics@master/ios/UI/2/3.png" />

连接2个StoryBoard

打开Main.storyboard, 为SecondViewController上的按钮建立一个IBAction, 然后在SecondViewController.swift里添加如下代码

 @IBAction func GotoSecondStoryBoard(sender: AnyObject) {

         let vc = UIStoryboard(name: "Second", bundle: nil).instantiateInitialViewController() as! UIViewController
        self.navigationController?.pushViewController(vc, animated: true)

    }

如果我们不设置Is Intial View Controller, 那么我们需要设置View Controller的StoryBoard Id, 然后使用如下代码

let vc = UIStoryboard(name: "Second", bundle: nil).instantiateViewControllerWithIdentifier("FirstView") as! UIViewController
self.navigationController?.pushViewController(vc, animated: true)

结果图 (Gif)

iOS UI系列 (一) :Auto Layout 高度三等分

首先我们创建一个Single View Application

然后我们向StoryBoard的ViewController 添加3个UIView, 设置不同的背景色,我们的目的是让这三个UIView垂直高度三等分。

接下来我们需要设置约速,我们让每个试图和周围的具体都是5,然后设置三个视图等高约束,具体看gif动态图, 如果看不清 右键图片–>open in new Tab

太白山游记

之前爬过陕西的很多山,华山、骊山、翠华山、王顺山、南五台、太平森林公园,祥裕。但是太白山则是爬完华山之后最想爬的山。因为它是秦岭山脉主峰,也是中国大陆青藏高原以东第一高峰,海拔3767米。更是长江和黄河两大水系分水岭,中国南北分界线,所谓人往高处走,我们都想爬的更高来看的更远。

由于我们公司一个团队做的很不错,去年获得了优秀团队的奖励,大家决定用团队奖励来活动一次。经过大家一致的表决,最后决定爬太白山。

出发(2015年6月5号)

我们计划周五12点出发,但是由于团队要发布系统,后来基本到下午1点才正式从西安出发。一路高速到绛法高速太白山方向,我们一行6个人,2辆车,去的时候由于很精神我开的相对较快,下高速等了同事大概10多分钟,原本以为下高速还要开很远,但是下了高速沿法场线差不多10分钟就到了太白山游客服务中心,问了一下要自驾进山必须是2.0以上的SUV, 我们一辆车是2.0T的但不是SUV, 我们另一辆是SUV, 但不是2.0以上的,只能把车停到停车场,收费是20元一天。

盘山公路

必须乘坐景区大巴,大概两个小时到下板寺,沿途有几个景点莲花峰瀑布,三国古栈道,盘山公路非常漂亮,终于明白了为啥必须是2.0以上的SUV才能进。

缆车

直接坐车到下板寺,海拔已经2700米,一下车,大家就感觉冷,而且开始有点高原反应了,由于缆车最后一趟是下午5点,我们只有10几分钟,赶紧买了缆车票,乘坐缆车。

小鸟独立枝头,此处已经3000米了,我们多想像飞翔的小鸟,这才叫傲世。

缆车上已经可以看到上板寺, 已经是云雾缭绕,高山的冷松

回望远处的山,我们已经与云同高,坐在缆车里感觉真的是冲上云霄。

下了缆车,兄弟们先合个影

天圆地方

在往上走40分钟左右,差不多到天圆地方,凌空玻璃, 我们有个兄弟害怕,不赶上去,拉都拉不上去,奇怪的是后来他还到了拔仙台。

佛光

继续往上走,云雾越来越近

突然,我们杨同学大喊一声: “看,佛光”,我们都停下来欣赏佛光,之前只听过,而且一直半信半疑,今天真的亲眼看见了。

中国南北分界岭

继续往上走,就进入中国南北分界岭,中间有一个外事检查站,老外是不能进去的,我不明白这是为什么,难道因为军事机密?

又见神奇佛光,每个人看到的中间的影子都是自己,你动他也动,你走他也走,真实佛在心中,佛就是你自己。

太白自然保护区

往前走几步,就到了太白自然保护区,又见佛光。

夜宿小文公

晚上7点多,终于到了小文公,听说到大文公需要两个小时,所以我们决定在小文公住,60元一个床,我们6个人买了4张床。 床是硬板床,被子也比较薄,安顿好后。此时已经感觉到比较冷了。

来时的路

山里的云海

大家已经感觉到很冷了,开始做俯卧撑。

由于高原反应,大家基本上都头疼,基本上一晚上没怎么睡着,还有人打呼噜,迷迷糊糊最后可能只睡了两个小时吧。

日出

早上5点半我们准备出发,我们决定在去大文公的路上看日出,早上看到的群山真的很漂亮,随着太阳的升起,每一分钟都不一样,从水墨画到山水画,任何大片都拍不出自然的本身,任何画家也画不出这么漂亮的山水,我驻足看了很久,心想,学画的要画山水,就应该在此住一段时间。

日出江花红胜火,日出的过程大概就2分钟,真的是很漂亮。 欣赏图吧,很遗憾没带单反,用我的iPhone 5S拍的。

去往大文公路上已经可以看到太白山顶,拔仙绝顶,但是想不到的是到那里比我们想像的时间长很多。

大文公

我们走了将近2小时,才到大文公,中间的路基本上都是石头路,不太好走,我们有2个人太慢了,可能是高原反应,我们走到大文公就留下了杨同学等另外的2个人。

我背的装备比较多,睡袋,急救包,野外小工具箱,我在这里都拿出来交给杨同学了,杨同学在这里等另外两个同事。说在此等我们三个人回来。

大爷海

很多人走到大文公就返回了,因为去大爷海要先爬一段山,从小文公到大文公很多人已经走的很累了。

真正的高山杜鹃。

驴友的尼玛堆

走了将近2个小时,终于到了大爷海,这段路是很难走的,先上山,然后下山,建议没有爬山经验的就不要去了,尤其是如果下雨下雪,路都基本走不成。

大爷海

六个人,到这里就三个人。

拔仙台

从大爷海去拔仙台,有两条路,左边的路比较陡峭,但是大概20多分钟就到了,右边比较平坦,但是要将近1个小时,于是我们选择的耗时较短的路。

山上还有些积雪没化

上山的路,全都是石头上走

拔仙台不远了

回望来时的路

马上到山顶了

往下看大爷海

已经到拔仙台,可以看到来时走的路都在3500米高的山顶,婉如一条丝带。

拔仙绝顶,一览众山小, 我想化作苍鹰,展翅翱翔!

我们三个人留下脚印

回来的时候,我们选择了走平坦的路,因为上山时基本都是手脚并用。

二爷海和三爷海

返程

回来的时候,我们两个同事明显感觉很累了,但是我看到乌云一来,就加快了脚步,我们返回大文公时,我们等着的同事已经走了,所以我们就一路不停的一直走会缆车,当我们到达缆车时已经是下午2点多了,至此我们已经来回共走了9个小时。我们回来时比同事预计的快了2个小时,主要是下山,高原反应没那么严重了。 到上板寺寺时,很多人问我们他们今天能否到拔仙台,我估计问这话的人,明天都到不了了,因为完全没有准备,还有一些女的就穿着短裙,问还有多远,我说你们还是回吧,不然就冻死了,她们能到小文公就不错了。接下来,就是座缆车,座大巴2小时,然后我们就开车返回西安了,回来时由于太累,基本上一路高速都没赶超过90km/h.

附录

要去太白山,而且要登顶的人,必须计划两天时间,而且要带冲锋衣,山上很冷,一定要带登山杖,要穿比较好的登山鞋。带些高热量的食物,如果高原反应严重的最好带点药。山上天气瞬息万变,最好带上防雨的装备,同时带上高能量食物和水,山上也有卖食物和水的,但是你要带钱。 建议在小文公住。