1 效率工具ShiftIt

可使用快捷键,快速便捷归置当前窗口。比如:

  • 当前窗口放到另一个显示器去
  • 当前窗口占用显示器左半边、右半边、上半边、下半边、正中间
  • 当前窗口变大、变小

ShiftItの使用の様子,https://www.youtube.com/watch?v=yFse0EFDpnM

2 方便学习的工具

用了几年了,较为科学,较为稳定,拿走不谢:链接

3 代码协作工具SourceTree

以SourceTree为主,结合command line和Github Desktop。不管Git的使用是否有鄙视链,我是挺喜欢用SourceTree的,推荐。当SourceTree搞不定的时候,也会直接用command line(iTerm,zsh)。有时SourceTree从Github上clone也会不顺,比如gist。Github Desktop在这方面就好得多。

时间过得快,距离上次更新文章已有7年。弹指一挥间。中断并非本意,而是7年前吃了一堑,想继续更新费点儿劲儿,又忙于其他,于是搁置了。

7年前,电脑丢了,很多资料、code,都没有push到远端,找不回来了。这个博客是用当时较为流行的Octopress搭建的。静态网站放在Github Pages。静态网站部分都还在,但文章markdown原始版本也遭遇丢失。吃一堑长一智,从那之后我倒是记住了,code不隔夜,都上云。此外电脑也经常用Time Machine备份。

这次得以重新开始更新,经历了4步:

  • Step 1,有想分享的东西,也有点时间,决定重新上路。
  • Step 2,选平台工具。可选的有微信公众号,简书,或者还是自己搭建。选自己搭建吧,因为目标也不是要触达多少人,还是满足自己乐趣为主。Octopress已经过时很久了,几年前就不再维护了,但有这么个蛋碴子在,给它续上,也是乐趣。所以没有选择用新的工具。
  • Step 3,恢复文章原始markdown版本。用了pandoc的ruby版,把文章从静态网站的html转为markdown。gist:https://gist.github.com/Seanli2013/f1e5608fd6f3591d4ddf57bc945ded87。 这一步耗费了不少时间,不过令人开心的是,最终it works,于是耗费的时间就变成了幸福的时间。
  • Step 4,重建Octopress+Github Pages。换了个Theme,换一换心情。http://octopress.org/docs/

读7年前的东西,真会感觉后背发凉。非常初级和稚嫩。可惜没办法,那就是真实的自己。

这7年,非常忙碌,经历虽多,也在忙碌中忙得碌碌无为。

或许这辈子一直都是个小人物,这我坦然接受。只不过不甘平庸的心一直在,到老了也一样会不停地在追求卓越。

总之,保重身体,人生还长,将来还是会做出成绩的。到时候回顾这一路的摸爬滚打,也许越不容易就会越增加幸福感吧。

iOS 播放 gif最棒的库,简单高效。

Animated GIFs implemented the right way on iOS


iOS上播放gif,没有自带的API,所以我找了现成的库,借过来使用。github上我对比了3个star数目较多的代码,最终选择了OLImageView

参与对比的是OLImageView,iOS_AnimatedGifAnimated-GIF-iPhone

选择合适的库

对比的指标,我选择

1. 效率高,占用内存小

只播放同样一个Gif,OLImageView占用内存是后两者的4/5。

(这个测试可能不完备,没有测试同时播放多个gif,或者播放不同类型gif的对比。但对我使用来讲,只播放这个Gif,就可以说明问题了。)

2. 代码维护活跃

OLImageView近来都有更新。

后两个中,Animated-GIF-iPhone是从iOS_AnimatedGif分出来的,两个都已经分别3年多、1年多没有更新了,虽然去年iOS_AnimatedGif的作者在blog上说要做对ARC的支持,但也没看更新。

OLImageView用法

大家可以在github上,看到OLImageView的用法,用法是描述如何从code中创建和使用,非常简单直白。

我在这里介绍一下实际在Storyboard中使用的方式。

1. 文件拖入工程

下载的OLImageView文件共有6个,但只要把下面四个文件拖进你的工程即可:

OLImageViewFilesInProject

2. Storyboard中设置UIImageView为OLImageView

正常拖入一个UIImageView,在这个view的CustomClass中设定为OLImageView:

CustomClass

在Outlet中,设定为OLImageView类型

Outlet

3. code中操作

在合适的地方,把gif设定进去,注意这里的UIImage要换成OLImage:

1
    [self.guideImageGif1 setImage:[OLImage imageNamed:@"peaceful.gif"]];//注意这里的image要使用OLImage

我的gif是在scrolllView中播放,所以我还需要设定frame:

1
    [self.guideImageGif1 setFrame:self.myScrollView.frame];

效果

我在“药提醒你”的帮助VC中,背景是个gif,具体效果,你可以下载个下来看看^_^——右侧侧边栏“我的产品”。

最后

要是有时间,你尽量阅读一下库的代码。知其然也知其所以然。

我在这里也就写写用法,比较浅显。目的是能让有同样需求的同学,减少一点儿时间开销,哪怕只减少了几分钟,也值得了。

环境和想要实现的功能

在Storyboard上,TabBarController作为rootViewController,此时想要在某个tab的VC中,点击个button,跳转到另外的tab上。如下图所示:

上图中,在第一个Tab上,点击“点击此处,去新建和管理提醒”,会跳转到第二个Tab,显示全部提醒的列表,来新建和管理提醒。

实现代码:

1
2
    AppDelegate *thisAppDelegate = [[UIApplication sharedApplication] delegate];
    [(UITabBarController *)thisAppDelegate.window.rootViewController setSelectedIndex:1];

分析: 我们在用代码创建app的时候,要在appDelegate中,去指定rootViewController。【不熟悉代码创建app的同学可以阅读这篇学习使用code实现iOS界面,在这篇blog中,推荐的IOS开发之纯代码界面—基本控件使用篇,非常适合新手学习code实现界面】在用Storyboard创建app的时候,虽然不用我们自己去指定rootViewController,但原理是一样的。

Storyboard中,app的入口箭头指向的VC,通常就是rootViewController。在这个例子中,就是UITabBarController。

通过

1
[[UIApplication sharedApplication] delegate]

得到自己这个appDelegate,通过调用

1
(UITabBarController *)thisAppDelegate.window.rootViewController

就得到了这个UITabBarController(的实例)。再使用UITabBarController(的实例)方法setSelectedIndex,去设定,要跳转到哪个Tab。

1
[(UITabBarController *)thisAppDelegate.window.rootViewController setSelectedIndex:1]

就是跳转到index为1的Tab,也就是第二个Tab了。

通过Storyboard搭建app框架,以及设计和实现一些view controller和view,是非常方便和高效的。

有时,同样一个scene(i.e. view controller),除了在Storyboard上通过segue达到以外,还需要在代码的某个地方,让它展现出来。

如何在代码中,调用一个已经在storyboard中设计好的scene呢?代码如下:

1
2
3
4
5
NSString * storyboardName = @"MainStoryboard_iPhone";
NSString * viewControllerID = @"ViewID";
UIStoryboard * storyboard = [UIStoryboard storyboardWithName:storyboardName bundle:nil];
MyViewController * controller = (MyViewController *)[storyboard instantiateViewControllerWithIdentifier:viewControllerID];
[self presentViewController:controller animated:YES completion:nil];

注:代码段来自Call storyboard scene programmatically (without needing segue)?

有两个注意的地方:
  1. 上面代码中的storyboardName不要包括”.storyboard”后缀。即,如果你的Storyboard文档叫做“Main.storyboard”,那么storyboardName应该叫@“Main”
  2. 注意:在Storyboard中,先给你的viewController加上ID,添加的地方如下图所示:在Indentity中的Storyboard ID。通过这个viewControllerID(图中的例子就是@“UserGuide”),在代码中找到这个vc。

storyboardID


关键字:代码中调用storyboard中的vc,代码中present storyboard scene

NSUserDefault,从名称也可看出,一般用来记录用户的设置的。这里介绍两种常用场景:检测应用(或app的某个版本)第一次运行记录用户设定的属性

原理

几句话说下我的理解:

  1. NSUserDefault使用方法standardUserDefaults得到全局的一个单例
  2. 在这个单例是个dictionary,即通过key-object来存、取信息
  3. 信息会存在plist文件中,你不删它,它就一直存在

检测app第一次运行

1
2
3
4
5
6
7
8
9
    // 以下这段代码,检查是否app的这个版本是否是第一次运行
    NSString *bundleVersion = [[NSBundle mainBundle] objectForInfoDictionaryKey:(NSString *)kCFBundleVersionKey];
    NSString *appFirstStartOfVersionKey = [NSString stringWithFormat:@"first_start_%@", bundleVersion];
    NSNumber *alreadyStartedOnVersion = [[NSUserDefaults standardUserDefaults] objectForKey:appFirstStartOfVersionKey];
    if(!alreadyStartedOnVersion || [alreadyStartedOnVersion boolValue] == NO) {
        [self versionFirstStart];// app的bundleVersion这个版本第一次运行,你希望这时做点儿什么
        [[NSUserDefaults standardUserDefaults] setObject:[NSNumber numberWithBool:YES] forKey:appFirstStartOfVersionKey];
    }
}

每次启动app时候,调用这段代码。检查一个叫做first_start_加版本号这么个key,对应的NSNumber类型Object,是否存在,或是否是0(NO),如果不存在,或者是0(NO),那么是这个版本的第一次运行,这时做你想在app第一次运行时做的事儿,比如[self versionFirstStart],之后在plist中添加这个key对应的NSNumber类型object,设置成1(YES)。这样,以后app只要未改变版本,启动时就再也不会执行[self versionFirstStart]了。

参见stackoverflow

P.S. 虽然我并未更改这段代码进行更多尝试,但肯定不一定非要NSNumber这个类型,只要plist能存储和读取的类型就可以。

记录用户设定的属性

想设定一个属性,你给这个属性起个独有的key,比如叫做@“your property key”。

设置属性:

1
[[NSUserDefaults standardUserDefaults] setObject:@"off" forKey:@"your property key"];

读取和判断属性:

1
2
3
if([[[NSUserDefaults standardUserDefaults] objectForKey:@"your property key"] isEqualToString:@"off"])
{
}

更多你要了解的NSUserDefault

1. 可存储的类型

NSUserDefault中存储的object的格式只能是以下列表中的类型,这是plist存储方式决定的。

1
2
3
4
5
6
7
array
dictionary
data
date
number - integer
number - floating point
Boolean

了解更多,可查阅Property List Programming Guide

2. 自动存储

使用NSUserDefault,默认是自动存储的,即你修改完之后,ios自动找个时候,同步(synchronize)一下内存和plist。

手动存储可直接调用synchronize方法:

1
[[NSUserDefaults standardUserDefaults] synchronize];
3. 查看目前NSUserDefaults standardUserDefaults中的内容

查看全部dict内容

1
NSLog(@"%@", [[NSUserDefaults standardUserDefaults] dictionaryRepresentation]);

当然,也可以查看全部的key

1
NSLog(@"%@", [[[NSUserDefaults standardUserDefaults] dictionaryRepresentation] allKeys]);

问题

windows8系统,装了Outlook2013,占用了C盘大约10G空间,主要都是数据文件(OST文件)占用的。希望能够把数据文件从C盘移至其他盘。并且账户是IMAP账户,不是Exchange。

google一下,绝大多数解决方案是针对以下两种情况:

  • 使用Exchange的账户,如何做到移动ost文件
  • 移动pst文件,而不是移动ost文件

都不适用。后来发现了这个解决方案,尝试后,成功!分享给大家:

解决方案

把ost文件移动到其他盘,在原来C盘的ost文件位置建立一个链接,链接到移动后的那个文件,大功告成。引用原作者的描述:

1
2
3
4
5
6
7
8
9
10
11
在Outlook2013 IMAP账户中

假设你目前的demo.pst文件在路径C:\Users\%username%\AppData\Local\Microsoft\Outlook下(已创建)

1. 关闭Outlook,移动此文件到D:\Outlook Files下。

2. 打开CMD,键入 mklink "C:\Users\%username%\AppData\Local\Microsoft\Outlook\XXXX.com.ost" "E:\Profile\Outlook\XXXX.com.ost"

3. 此时C:\Users\%username%\AppData\Local\Microsoft\Outlook下会有一个类似于快捷方式的同步文件demo.ost存在(0KB)。

4. 打开Outlook,IMAP账户仍然会挂接到C:\Users\%username%\AppData\Local\Microsoft\Outlook\demo.ost上,但该文件只是D盘下数据文件的映射,实际不消耗任何磁盘空间。

原文地址:Outlook2013 迁移OST存储位置

注意事项

使用的过程中有需要注意的地方:

1~ 需要使用管理员身份运行cmd

windows8的应用程序那儿,搜素cmd,出来“命令提示符”,右键点击,这时屏幕下方会出现几个选项,选择“”以管理员身份运行”

2~ 建立符号链接的位置的磁盘应该是NTFS格式

建立符号链接的位置,就是mklink后紧跟的参数的位置,如果不是NTFS格式的盘,恐怕就建立不了了。

P.S. 我更喜欢Mac

虽然windows是个很伟大的系统,并且其中的很多软件也异常优秀,但我已经很久不用windows了。日常使用,我觉得Mac系统是胜过windows的,尤其是对编程写代码的人。

但windows你也得熟悉,一方面由于别人的或公共的电脑windows占比很高,另一方面老婆向你求助的时候,你得帮忙解决问题啊,就像今天这个分享写的这事儿。

现在,iOS系统已经发展到iOS7,而iOS5时引入的ARC技术早已成为主流了。所以iOS新手们对ARC技术已经习以为常了吧,对之前的手工内存管理可能完全不了解,因为基本用不到。ARC又是如此简单,貌似也没有什么必须学习的。但了解一下ARC的原理原则还是必须的——因为了解技术的原理可以更好地对技术进行应用嘛。

本文算是阅读 Beginning ARC in iOS 5 Tutorial Part 1 (翻译在 iOS 5 ARC 入门 (1/3) 翻译的同学很有爱也很辛苦,但有些地方有错误,所以读原文会比较好。)

ARC简介

ARC,Automatic Reference Counting,在iOS5引入。

原理

简单说是代码在编译阶段,由编译器(LLVM 3.0)自动生成实例的引用计数管理的一些代码(插入retain/release等),起到内存管理的作用。

在ARC之前

在ARC之前,需要手工管理内存,原则是:

  • 如果你想保持一个对象可用,除非它已经被retain了,否则就需要retain它
  • 如果不再需要一个对象,就需要release它,除非它已经被release了(通过autorelease)

用ARC,程序会变慢吗?

不会!

ARC就是在需要retain和release的地方为你插入它们——这就是ARC和手工管理内存一样快的原因,当然有时ARC还会更快,因为它在后端还进行了一些优化操作。

ARC使用

这里只介绍个ARC使用方法的小子集,即仅记录了我觉得有意思的几个概念原则。ARC使用全集请看Beginning ARC in iOS 5 Tutorial Part 11

strong、weak

  • 有strong指针指向那个对象,那个对象就一直存在在内存中。这个原则对实例变量、属性、局部变量都使用
  • 默认所有实例变量局部变量等都是strong的指针,strong表示指针是变量的所有者
  • weak也可以指向一个对象,但不能是所有者
  • zeroing weak指针,是指weak指向的对象被释放了,weak指向的变量的值自动变为nil,这个特性防止了指向一个被释放的内存(例如悬空指针、僵尸等这样的说法这种问题就没有啦)
  • weak不常用,经常使用在父子对象上,因为父有strong指向子,子指向父的时候就只能用weak,常见的datasource、delegate都是这样

ARC特殊注意的地方

  • ARC不适用于Core Foundation 或 malloc() 和 free(),后者还是要手工管理内存
  • ARC 有效的时候,由于编译器帮我们做了内存管理的工作,所以我们不需要太担心。但是当与 ARC 管理以外的对象类型交互的时候,就需要特殊的转型关键字,来决定所有权的归属问题。比如“__bridge”。进一步了解可阅读参考文件2
  • 使用ARC,仍然要想着谁持有谁,后者的生命周期是怎么样的等,因为如果不释放指针,被持有者就一直在内存中

结语

易飞扬对ARC的7篇博文很值得推荐,大家想深入了解ARC原理可以去阅读: iPhone开发之深入浅出,注:要跳墙。

参考文献Beginning ARC in iOS 5 Tutorial Part 1中说:ARC是代表着OC的未来(大概因为ARC之前的内存管理是开发者们曾经的噩梦吧)。A smart developer tries to automate as much of his job as possible, and that’s exactly what ARC offers: automation of menial programming work that you had to do by hand previously. To me, switching is a no-brainer.

技术在不断飞速演进,做工程开发的我们,紧盯技术发展趋势,勇于接受新的东西。


  1. Beginning ARC in iOS 5 Tutorial Part 1

  2. iPhone开发之深入浅出 注:该文需要跳墙

iWork免费了!以前仰望着的128元的产品,现在终于可以免费使用了!不过,据说需要买最新的硬件才能享受免费。于是就有了下面:老旧mac得到免费iWork的方式。

注:第二步中可能需要你有美国账号(其他国家的账号没试过,中国的不行),如果没有美国账号,据说更改系统的语言为英文也行。

第一步,装个09年的trial版

下载地址可以去这里

安装可能遇到的问题

无法open安装包

双击安装时,出现下面的对话框:

CannotOpen

解决方式

不双击,而是按住Control键,单击。此时在出现的菜单中选择open。

ControlClick

此时再选择open,就可以啦!

ChooseOpenAgain

安装完成后进入第二步。

第二步,在App Store进行免费更新

1. 打开App Store切换国家

在AppStore页面右下角,有当前国家的标志,点击这里进行切换。点击选择美国后,App Store市场切换到美国:

ChangeCountry

“128元”的标志不见了,取而代之的是“update”。这时需要你的美国账号了。(没有美国账号的同学试试把系统语言改为英文,据说也行) CanUpdateNow

选择update,输入美国账号,搞定!


苹果公司让这些产品免费,真挺好,赞一个!

Autolayout是非常先进的一个技术。使用这种技术,适应不同设备屏幕大小差异或设备翻转时对界面的要求,变得很容易。这种技术提供了一种灵活的机制来描述界面上各控件的位置关系。

Xcode5使Autolayout技术更容易使用了。 之前,我对Autolayout只是听说有这种机制,但不知原理、用法。于是阅读了下面的两篇文章(作者: Matthijs Hollemans。目前貌似还没有翻译),算是在Storyboard/Xib上会用了。

以下作为阅读笔记,记录应该了解的使用Autolayout的要点(环境是Xcode5,iOS7SDK,Storyboard/Xib)。

原理要点

  • Autolayout基本是靠constraints来描述两个view之间的位置关系
  • Autolayout与以往的frame、bound、center包括autosizing mask等方式都不同,这是一个新的技术,使用Autolayout时候就不用考虑以上那些方式啦,不用再纠结这个view的位置是(x,y,width,height)了!
  • Autolayout描述位置关系的这两个view,或者是上下层关系,或者是同一层关系。即父子关系或都是父的子(兄弟关系^_^)
  • Constraints都是NSLayoutConstraint的对象,有一些属性可以在Attributes inspector中修改。当然也可以通过code的方式来实现Storyboard/Xib上的操作

使用方式

这里只介绍Storyboard/Xib使用方式,如果想了解code实现,还要继续阅读其他资料。

设计及实现方法:

理清view想要摆放的位置逻辑(设计),根据这个逻辑来设置Constraints(实现)。比如这个Button要距离那个Button固定20个点的距离,并且两个Button要顶端对齐等。把这些逻辑条件变成constraints,当constraints完备到可以确定view的位置时,就完成了设计和实现。

在Storyboard/Xib上使用

  • Autolayout的checkbox默认是check上的,这个配置是对整个Storyboard或整个Xib生效的

  • 可以设置Constraints的地方

    1 Editor菜单下的Pin以上的4个菜单

    Editor

    2 在View层次列表中选中Constraints后,在Attributes Inspector中设置

    viewhierachy Inspector

    3 最方面快捷的方式是在悬浮在界面编辑右下角的几个图标

    quick
menu

  • 蓝色的辅助线:表明Constraints已经足以说明这个view的位置了

blue

  • 橙色的辅助线:表示constraints没有完备到可以说明这个view的位置

orange

  • 橙色的辅助线上的数字:有时是正数,有时是负数。当你设定或更改了Constraints的时候,可能Constraints与界面上你放置的view的位置是不同的。系统会以Constraints为准,界面上提示你橙色辅助线,线上的数字是这个view的位置与Constraints的差距。这时可以在“Resolve Auto Layout Issues”中选择update frame,这样这个view会自动移动到Constraints所指示的地方;也可以update constraints,这时view的位置不变,constraints变为与界面上的view位置一致的数值

  • 对没有提供Constraints的view,系统会自动加上constraints,这些constraints是界面上不可见的。这一点是Xcode5与Xcode4在Autolayout技术升级上最大的改进!Xcode4是系统强加constraints,往往会对开发者进行了干扰,因为强加的Constraints往往不是你想要的。Xcode5的这个改进方便了开发者按照自己的意图去设计和实施:首先不用去修改系统强加的constraints;其次有些view的位置你不需要增加Constraints,就可以不用理会。注:这种自动给View加Constraints的方式只适用于你一个Constraints都没加的情况,如果你加了x方向的,y方向的也需要手动添加。

  • preview:preview可真方便,你一边在左侧(Portrait、4寸屏)设计实施,一边在preview中看到lanscape的样子或者在3.5寸屏中的样子

preview

  • 可设置的constraints的类别:
    1. 几个View之间对齐
      • 边缘对齐、中心对齐等
      • 这几个view宽、高相等等
    2. 相对距离。
      • 距离最近的一个view的距离
      • 两个view之间的距离
      • 距离顶端、底端、左边缘、右边缘的距离
      • 自己的宽、高

接下来

以上是一些基础要点,当你用Storyboard/Xib做设计的时候,基本就够用啦。如果觉得这些要点不够,可以参照Matthijs Hollemans在这两篇文章中举的例子,这个例子将带你进行一步步操作。

有些特殊的场景,使用Storyboard/Xib的autolayout是无法实现,需要代码方式的autolayout来实现。代码实现主要围绕着对NSLayoutConstraint对象的操作。具体如何实现,等需要的时候再找时间研究了。