New Mac Setup

换了 SSD,重新配置了开发环境,简单留个笔记。

  1. Mac App Store 下载 Xcode,安装 Command Line Tools 方便编译。MAS 下载的一个好处就是后续可以增量更新。
  2. 安装 Homebrew,通过 brew 安装管理其他工具 git,zsh,MacVim,redis,PostgreSQL 等。
  3. 配置 oh-my-zsh,懒人必备。
  4. clone back dotfils from GitHub. 每个人都应该在 GitHub 等托管一份自己的配置文件,DRY。
  5. brew install rbenv ruby-build,主要是给 Octopress 用,之前用 rvm 过于庞大复杂,rbenv 就简单不少。
  6. 配置 Python virtualenv 环境,easy_install pip and use pip to install others.

换硬盘就显示了云存储的方便。Firefox Sync 很快就是自己顺手的浏览器,Dropbox 同步 nvALT 笔记,Alfred 等软件配置,只需一个账号你的数据、习惯随手就来,这也就是 Chromoe OS 带来的未来。

TP-Link WR941N 刷 OpenWrt

硬件版本 TP-Link WR941N V4/V5 00000000,软件版本 3.11.7 build 100723,从 OpenWrt trunk 下载对应固件 openwrt-ar71xx-generic-tl-wr941nd-v4-squashfs-factory.bin。其他型号参考 Table of Hardware 下载固件。

登录路由器升级固件,待路由自动重启后 telnet 192.168.1.1 连上路由器,passwd 设置密码,之后就可以通过 ssh [email protected] 登录路由器。

OpenWrt 默认没有开启无线网络,参考 TP-Link TL-WR941ND 手动修改 vi /etc/config/wireless: (修改之前最好备份一下配置文件)

config wifi-device  radio0
        option type     mac80211
        option channel  11
        option hwmode   11ng
        option path     'pci0000:00/0000:00:00.0'
        option htmode   HT20
        list ht_capab   SHORT-GI-40
        list ht_capab   TX-STBC
        list ht_capab   RX-STBC1
        list ht_capab   DSSS_CCK-40
        # REMOVE THIS LINE TO ENABLE WIFI:
        # option disabled 1 (删除或注释这一行)

config wifi-iface
        option device   radio0
        option network  lan
        option mode     ap
        option ssid     OpenWrt
        option encryption psk (默认没有加密,修改为 psk)
        option key      xxxxxxxxx

重启路由网络:

/etc/init.d/network restart

配置 PPPoE,vi /etc/config/network:

config interface 'wan'
        option ifname 'eth1'
        option proto pppoe
        option username 1234567
        option password 7654321
        option macaddr xx:xx:xx:xx:xx:xx (克隆路由器网卡地址)

再次重启路由网络进行拨号。

安装 LuCI web 界面,这样就可以在浏览器操作路由:

opkg update
opkg install luci
/etc/init.d/uhttpd enable
/etc/init.d/uhttpd start

现在就可以通过 http://192.168.1.1 修改路由器配置。

如果网络修改失败不能 ssh 登录,可以进入安全模式恢复:

路由上电时,灯会全亮一下,这时你要全神贯注了,当sys灯再次亮时,要立刻按reset2-3秒,然后你就会发现sys灯快闪了。这说明,安全模式成功了!

本机 IP 改为 192.168.1.5,telnet 192.168.1.1 连上,然后 firstboot 恢复。

Get declared property for object

获取对象的 property 属性列表:

objc_property_t *class_copyPropertyList(Class cls, unsigned int *outCount)
objc_property_t *protocol_copyPropertyList(Protocol *proto, unsigned int *outCount)

sample, via Declared Properties:

#import <objc/runtime.h>

id LenderClass = objc_getClass("Lender");

unsigned int outCount, i;
objc_property_t *properties = class_copyPropertyList(LenderClass, &outCount);

for (i = 0; i < outCount; i++)
{
    objc_property_t property = properties[i];
    fprintf(stdout, "%s %s\n", property_getName(property), property_getAttributes(property));
}
free(properties);

拿到 property 列表就可以很方便做一些东西,比如 autodescribe,根据列表取值然后组装成对象 description。再比如配合 NSCoder 做 NSObject 的序列化

- (id)initWithCoder:(NSCoder *)decoder
{
    self = [super init]
    if (self)
    {
        Class clazz = [self class];
        NSUInteger count;

        objc_property_t *properties = class_copyPropertyList(clazz, &count);
        NSMutableArray *propertyArray = [NSMutableArray arrayWithCapacity:count];
        for (int i = 0; i < count ; i++)
        {
            objc_property_t property = properties[i];
            const char *propertyName = property_getName(property);
            [propertyArray addObject:[NSString stringWithCString:propertyName encoding:NSUTF8StringEncoding]];
        }
        free(properties);

        for (NSString *name in propertyArray)
        {
            id value = [decoder decodeObjectForKey:name];
            [self setValue:value forKey:name];
        }
    }
    return self;
}

- (void)encodeWithCoder:(NSCoder *)coder
{
    Class clazz = [self class];
    NSUInteger count;

    objc_property_t *properties = class_copyPropertyList(clazz, &count);
    NSMutableArray *propertyArray = [NSMutableArray arrayWithCapacity:count];
    for (int i = 0; i < count ; i++)
    {
        objc_property_t property = properties[i];
        const char *propertyName = property_getName(property);
        [propertyArray addObject:[NSString stringWithCString:propertyName encoding:NSUTF8StringEncoding]];
    }
    free(properties);

    for (NSString *name in propertyArray)
    {
        id value = [self valueForKey:name];
        [coder encodeObject:value forKey:name];
    }
}

也可以拿到成员变量列表: class_copyIvarList(Class cls, unsigned int *outCount). Objective-C Runtime 有很多东西可以学习的。

Modern iOS Development

iOS 开发是一个进化非常快的技术领域,每年一更新的 iOS SDK 都会带来很多新东西,所以如果你现在用着和一年前一样的 code 做产品,虽然功能上没有差别,但是从技术上来说自身的成长进步非常有限。简单总结一下现在比较 modern 的开发方式。(截至 2012 年底)

ARC

iOS SDK 5 引进来的 ARC 已经非常成熟,是时候用了。ARC 可以大大减少各种不小心造成的内存泄漏,减少各种费脑子的内存问题 debug,这时候再手动内存管理完全是给自己增加工作。现在主流第三方库都已经 ARC ready 了,迁移成本很小。

Blocks

并不是说 delegate 有多不好,用 blocks 封装的接口使用起来非常轻便,尤其是网络请求等需要异步操作的时候,简单明了。

New Objective-C Literals

参考 New Objective-C Literals:

NSInteger _appid = 12345;
NSArray *array = @[ @"title", @(_appid)];

NSString *title1 = array[0];
array[0] = @"newTitle";

NSDictionary *dict = @{
    @"appid" : @(_appid),
    @"title" : _title,
};

NSString *title2 = dict[@"title"];

NSNumber *intNum = @123;
NSNumber *floatNum = @1.23f;
NSNumber *boolNum = @YES;

掌握新语法并不能说明技术能力有多高,但可以减少很多体力劳动,不需要敲很多 objectAtIndex: objectForKey:,代码结构也更为清晰。

@Synthesize by Default

以前:

@interface Person : NSObject
{
    NSString *_name;
}

@property (nonatomic, strong) NSString *name;

@end

@implementation Person

@synthesize name = _name;

@end

现在:

@interface Person : NSObject

@property (nonatomic, strong) NSString *name;

@end

@implementation Person

@end

Xcode 4.4+ 会自动做 @synthesize,成员变量都可以不用手动声明,直接下划线开头 _var 形式。一来节省代码量,二来鼓励用 property,Always use accessor methods, Except in initializer methods and dealloc.,保证健壮性。

Modern Library and Tools

iDev 免不了要用到很多第三方库,这时候最好选用那些较新且成熟的库,是否支持 ARC 等。比如 AFN vs ASI,我个人非常喜欢 AFN 的设计,简单方便易扩展。

第三方库多了管理就是问题,现在有了 CocoaPods 一切变得都很简单,团队之间的分享协作也会方便很多,不会出现两边因为公共库版本不一致带来 bug 问题。

参考:

  • WWDC 2012 Session 405 - Modern Objective-C
  • WWDC 2012 Session 413 - Migrating to Modern Objective-C.

New Objective-C Literals

NSArray:

NSInteger _appid = 12345;
NSArray *array = @[ @"title", @(_appid)];

NSString *title = array[0];
array[0] = @"newTitle";

NSDictionary:

NSDictionary *dict = @{
    @"appid" : @(_appid),
    @"title" : _title,
};

NSString *title = dict[@"title"];
dict[@"title"] = @"newTitle";

NSNumber:

NSNumber *intNum = @123;
NSNumber *floatNum = @1.23f;
NSNumber *boolNum = @YES;

More: Objective-C Literals

iOS URL Loading System

iOS 整个网络请求系统分为这几部分:

  • URL Loading:
    • NSURLRequest / NSMutableURLRequest
    • NSURLResponse / NSHTTPURLResponse
    • NSURLConnection
  • Cache Management
    • NSURLCache
    • NSCachedURLResponse
  • Authentication and Credentials
    • NSURLCredential
    • NSURLCredentialStorage
    • NSURLAuthenticationChallenge
    • NSURLAuthenticationChallengeSender
    • NSURLProtectionSpace
  • Cookie Storage
    • NSHTTPCookie
    • NSHTTPCookieStorage
  • Protocol Support

参考 URL Loading System Overview.

禁用 git merge 完成后的提交说明

Git 1.7.10+ 版本对 git merge 做了一个改动,就是 merge 成功后会自动打开编辑器等待输入 merge 提交说明,而之前版本是自动完成这个 log。Linus 大神说之前的做法其实是一个设计失误 via

we never even fire up the editor by default for a “git merge”, but we do for a “git commit”. That was a design mistake, and it means that if you want to actually add a note to a merge, you have to do extra work.

然而大部分时候我们 merge 的时候都不太会去手动添加 merge log,那么这个功能就是个干扰,每次都要手动去关掉编辑器。这里 找到一个解决方案:

export GIT_MERGE_AUTOEDIT=no

Done.

CocoaPods Notes

CocoaPods, an Objective-C library dependency manager.


安装:

sudo gem install cocoapods
pod setup //初始化更新 Specs

新建项目,在项目 根目录 新建 Podfile 文件:

platform :ios, '5.0'

pod 'AFNetworking'
pod 'SDWebImage', :git => 'https://github.com/appwilldev/SDWebImage.git'
pod 'JSONKit', :podspec => 'https://raw.github.com/gist/1346394/1d26570f68ca27377a27430c65841a0880395d72/JSONKit.podspec'

Podfile 可以指定具体代码地址,具体一个 commit/tag,或者具体 podspec (多用于私有库)。安装相关 Pods:

pod install

CocoaPods 会新建一个和项目同名的 workspace,以后就用这个 workspace 来打开项目。需要新加或删除库的话就直接编辑 Podfile 然后再 pod install.


添加 CocoaPods/Specs 没有或私有库:

pod spec create WeiboEngine https://github.com/fannheyward/WeiboEngine
// 如果指定 Github 链接,会获取代码库相关信息来初始化 podspec.

自动生成 WeiboEngine.podspec 文件,按照模板编辑修改相关作者、项目主页等信息。重点是 s.source 设置。s.source 指定代码库地址,支持 git/hg/svn 代码库,支持 http://example.com/source.zip 代码压缩包,支持用 :tag :commit 指定具体版本。s.source_files 指明代码目录文件。

验证生成的 podspec 文件是否合法正确:

pod spec lint WeiboKit.podspec

验证通过后把 podspec 保存在 ~/.cocoapods/master/ 即可直接通过 pod install 进行安装;也可以向 CocoaPods/Specs 提交新建的 spec:

pod setup --push
pod push master

iOS 6 下自动旋转的变化

iOS 6 SDK 中的屏幕自动旋转有了一些变化,简单纪录之。举例:Master-Detail 类型 App,master ViewController 不支持屏幕旋转, detail ViewController 支持屏幕旋转。

在 Info.plist 或 Target-Summary 启用自动旋转,选中需要的 Supported Interface Orientations。新建 UINavigationController+Autorotation.h category,根据需要禁用最底层 NavController 的自动旋转:

- (BOOL)shouldAutorotate
{
    return NO;
}

在 AppDelegate 设置 window.rootViewController = navController;,由于 shouldAutorotateToInterfaceOrientation: 从 iOS 6 起 deprecated,在需要自动旋转的 viewController 改用 supportedInterfaceOrientations+preferredInterfaceOrientationForPresentation

- (BOOL)shouldAutorotate
{
    return YES;
}

- (NSUInteger)supportedInterfaceOrientations
{
    return UIInterfaceOrientationMaskAllButUpsideDown;
}

- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation
{
    return UIInterfaceOrientationLandscapeRight;
}

几个需要注意的地方:

  1. window 需要设置 rootViewController,[window addSubview:navController.view]; 无效;
  2. shouldAutorotate 在最底层设置才有效;
  3. presentModalViewController 下用之前的自动旋转控制无效,须用 category 解决。

NSLinguisticTagger Notes

NSLinguisticTagger 是 iOS 5+/OS X 10.7+ 引入的自然语言智能分析类。一个简单的 sample:

NSString *text = @"The iPhone is a line of smartphones designed and marketed by Apple Inc. The iPhone runs Apple's iOS mobile operating system, originally named iPhone OS. The first iPhone was unveiled by then CEO of Apple Steve Jobs on January 9, 2007, and released on June 29, 2007. The most recent iPhone, the 5th generation iPhone 4S, was released in October 2011. iPhone是苹果公司旗下的一个智能手机系列,此系列手机搭载苹果公司研发的iOS手机操作系统。第一代iPhone于2007年1月9日由时任苹果公司CEO的史蒂夫·乔布斯发布,并在6月29日正式发售;最新的iPhone 4s于2011年10月4日发布,并于同年10月14日正式发售。"; // text from Wikipedia.

NSArray *schemes = [NSArray arrayWithObject:NSLinguisticTagSchemeNameTypeOrLexicalClass];
NSLinguisticTagger *tagger = [[NSLinguisticTagger alloc] initWithTagSchemes:schemes options:0];
tagger.string = text;
[tagger enumerateTagsInRange:NSMakeRange(0, text.length)
                      scheme:NSLinguisticTagSchemeNameTypeOrLexicalClass
                     options:NSLinguisticTaggerOmitWhitespace | NSLinguisticTaggerOmitPunctuation // 忽略空格和标点
                  usingBlock:^(NSString *tag, NSRange tokenRange, NSRange sentenceRange, BOOL *stop) {
                      NSLog(@"%@ is a %@", [text substringWithRange:tokenRange], tag);
                  }];

// OR

[text enumerateLinguisticTagsInRange:NSMakeRange(0, text.length)
                              scheme:NSLinguisticTagSchemeNameTypeOrLexicalClass
                             options:NSLinguisticTaggerOmitWhitespace | NSLinguisticTaggerOmitPunctuation
                         orthography:nil
                          usingBlock:^(NSString *tag, NSRange tokenRange, NSRange sentenceRange, BOOL *stop) {
                              NSLog(@"%@ is a %@", [text substringWithRange:tokenRange], tag);
                    }];

结果输出:

2012-09-11 11:56:45.192 LinguisticTaggerSample[3342:c07] The is a Determiner
2012-09-11 11:56:45.193 LinguisticTaggerSample[3342:c07] iPhone is a Noun
2012-09-11 11:56:45.193 LinguisticTaggerSample[3342:c07] is is a Verb
2012-09-11 11:56:45.193 LinguisticTaggerSample[3342:c07] a is a Determiner
2012-09-11 11:56:45.194 LinguisticTaggerSample[3342:c07] line is a Noun
2012-09-11 11:56:45.194 LinguisticTaggerSample[3342:c07] of is a Preposition
2012-09-11 11:56:45.194 LinguisticTaggerSample[3342:c07] smartphones is a Adverb
2012-09-11 11:56:45.194 LinguisticTaggerSample[3342:c07] designed is a Verb
2012-09-11 11:56:45.195 LinguisticTaggerSample[3342:c07] and is a Conjunction
2012-09-11 11:56:45.195 LinguisticTaggerSample[3342:c07] marketed is a Verb
2012-09-11 11:56:45.195 LinguisticTaggerSample[3342:c07] by is a Preposition
2012-09-11 11:56:45.196 LinguisticTaggerSample[3342:c07] Apple is a OrganizationName
2012-09-11 11:56:45.196 LinguisticTaggerSample[3342:c07] Inc is a OrganizationName
...
2012-09-11 11:56:45.203 LinguisticTaggerSample[3342:c07] Steve is a PersonalName
2012-09-11 11:56:45.203 LinguisticTaggerSample[3342:c07] Jobs is a PersonalName
...
2012-09-11 11:56:45.222 LinguisticTaggerSample[3342:c07] iPhone is a Noun
2012-09-11 11:56:45.223 LinguisticTaggerSample[3342:c07] 是 is a Particle
2012-09-11 11:56:45.223 LinguisticTaggerSample[3342:c07] 苹果 is a Verb
2012-09-11 11:56:45.223 LinguisticTaggerSample[3342:c07] 公司 is a Particle
2012-09-11 11:56:45.224 LinguisticTaggerSample[3342:c07] 旗下 is a Verb
2012-09-11 11:56:45.224 LinguisticTaggerSample[3342:c07] 的 is a Particle
2012-09-11 11:56:45.224 LinguisticTaggerSample[3342:c07] 一 is a Verb
2012-09-11 11:56:45.288 LinguisticTaggerSample[3342:c07] 个 is a Particle
2012-09-11 11:56:45.288 LinguisticTaggerSample[3342:c07] 智能 is a Verb
2012-09-11 11:56:45.289 LinguisticTaggerSample[3342:c07] 手机 is a Particle
2012-09-11 11:56:45.289 LinguisticTaggerSample[3342:c07] 系列 is a Verb
...
2012-09-11 11:56:45.310 LinguisticTaggerSample[3342:c07] 史 is a Verb
2012-09-11 11:56:45.311 LinguisticTaggerSample[3342:c07] 蒂 is a Particle
2012-09-11 11:56:45.311 LinguisticTaggerSample[3342:c07] 夫 is a Verb
2012-09-11 11:56:45.311 LinguisticTaggerSample[3342:c07] 乔 is a Particle
2012-09-11 11:56:45.312 LinguisticTaggerSample[3342:c07] 布 is a Verb
2012-09-11 11:56:45.312 LinguisticTaggerSample[3342:c07] 斯 is a Particle

对英文的分析要好于中文。不同的 scheme 有不同的返回结果,包括文本语言等。详细文档 NSLinguisticTagger Class Reference.

PS:可以用这个做一个微博关键词分析,罗列出自己微博最多的关键词。