KVC and KVO

KVC

KVC 是 Key-value coding 的缩写,是一种通过 key-value 的方式获取对象属性的机制。 这个 key 是一个 String 的唯一标示符,这个 key 的 name 约定是必须是 ASCII 码、小写字母开头、中间不能有空格。

让一个类实现 KVO 的方式是遵循 NSKeyValueCoding 这个协议,该协议中定义了 2 个方法:valueForKey: and setValue:forKey:. 这两个方法用来通过 key 访问和获取对象属性。

More about KVC

KVO

Apple Document about KVO

KVO 的实现方式:isa-swizzing

Lightweight Key-Value Observing

聊聊 iOS 开发里的 MVC 模式

Image1 icon

最近项目要重构,首当其冲的就是代码结构,因为很多原因之前很少考虑代码结构的事情。终于要抽出一部分时间来重构这个项目,首先是整个项目的结构和代码逻辑不太符合 MVC,又顺便了解了一下 iOS 里的 MVC 模式的概念。首先 MVC 模式不光定义了每一部分在整个应用中扮演的角色,也定义了各个部分相互沟通交流的方式。每一部分都扮演着不同的角色,分工明确,降低耦合,减少依赖,使得每一部分都能够复用,这也是 MVC 模式的意义和目的所在。下面就简单描述一下 MVC 模式里对每一个角色的职能和责任。

Model

Model 层对象应该是封装了一定的数据规范,并且定义了管理和处理这些数据的逻辑和计算。简单说就是 Model 对象不仅定义了数据结构,还要包括对数据结构的操作和处理逻辑。比如从网络、sqlite、UserDefault 里获取需要在 View 里展现的数据以及存入用户感兴趣的数据等等。其实 Model 里是包含业务逻辑的,这一点和 Web 开发差异很大,之前在用 Java 开发 Web 程序时使用 MVC,M 就是 POJO,只包括定义数据结构,不包含对这些数据的处理 (处理的部分放在一个叫 Service 层里),也称之为贫血模型。相对应的充血模型就类似这里的 M,是包含对数据的操作和处理,ROR 里的 ActiveRecord 就是这样的。

View

View 层的理解就很简单了,就是用户能看得见的东西,比如 UIKit 里的各种系统自带控件等。View 对象应该知道如何把自己展示给用户并且对用户的操作做出回应。View 层对象的主要用途在于展示出应用的 Model 层数据并且允许用户通过交互修改这些数据。

Controller

Image2 icon

Controller 层对象相当于一个中间人,负责协调应用中的 View 层对象和 Model 层对象的关系,也是 View 和 Model 相互沟通的媒介。除此之外,Controller 还负责组织和协调应用中的任务以及管理其他对象的声明周期。

相互的沟通

Image3 icon

Model 层不直接和 View 沟通,当 Model 层对象改变(比如通过网络获取到了新的数据),它会通知 Controller 对象,Controller 对象收到通知更新对应的 View。当 View 层有改变(比如用户通过交互创建或修改了数据,称为 User Action),View 会通过 Controller 对象去创建或修改 Model 层的数据。 Model 层和 View 层是相互不知道对方的,它们的沟通是通过 Controller 这个中间人来协调处理。

Jekyll 设置友言为社会化评论组件

Jekyll 默认的社会化评论组件是 disqus,第三方 SNS 是 facebook,twitter 等,不方便大陆用户使用,发现国内也有类似的社会化评论组件,比如友言等,经比较发现友言更简单易用。

替换的整个过程很简单,分为两大步: 首先要注册一个友言的账户,点击获取代码,就能获得一段和你用户相关的 js 代码。类似下面这样:

1
2
3
4
<!-- UY BEGIN -->
<div id="uyan_frame"></div>
<script type="text/javascript" id="UYScript" src="http://v1.uyan.cc/js/iframe.js?UYUserId=YOUR_USER_ID" async=""></script>
<!-- UY END -->

然后要切换到本地来,由于 Jekyll 的评论组件是插件式的,很方便修改,分为下面 2 个步骤

  1. 修改_config.yml 文件中 comments: 下的 provider: 的值为 custom(默认是 disqus)
  2. 在_includes 目录下新建一个目录 custom, 在 custom 目录下新建一个文件 comments,文件的内容就是上面从友言获得的那段代码。

push 到 GitHub,刷新页面查看效果吧

这么做的原理很简单,看一下 youname.github.com/_includes/JB/comments 文件的 看最后一个 when 语句,当 site.JB.comments.provider 的值为 custom 时,就加载 custom/comments 文件,那么其实 site.JB.comments.provider 的值就是刚才在_config.yml 中设置的那个 provider,这样就能说的通了。

Have fun!

鲜为人知的但很有用的 Java 类

作者:Dustin Marx 发表日期:Fri, 03/02/2012 - 23:10.

Reddit Java 网站最近有一个题目为“分享 Java 标准类库中一些有用的类”的讨论话题,注解栏为“有很多平常我们没有认识到的类,分享一些你经常使用而我们可能没有意识到的类吧!”。在这篇文章中,我看到下面回复超过 40 的一些类(大部分是 JDK 中的)。

有一些回复者分享的是与并发相关的 Java 类,如 Executors, java.util.concurrent.CountDownLatch, java.util.concurrent.atomic.AtomicInteger, ThreadLocal, java.util.concurrent 以及包下的所有类以及java.util.concurrent.atomic.

还有一些与 String 处理相关的类也被提到了,包括 StringBuffer, 和 StringBuilder. 我在博文 String, StringBuffer, and StringBuilder: There Is A Performance Difference 中也提到了这些与 String 相关的类。其他与 String 相关并被提到的包括java.util.StringTokenizerApache Commons‘ StringUtils (在我的文章 Checking for Null or Empty or White Space Only String in Java 中也有提到). java.util.Scanner 类也可以让简化文本解析。

在用户界面上, java.awt.geom 包, java.awt.Desktop 以及 javax.swing.SwingUtilities 被提到。 java.awt.Point 被高亮显示,原因总结为:”任何两个 int 值对可以很简单的被用来代替数组传递给函数,或者从函数中返回,都可以使用 Point 类”。java.awt.Robot 类也在文中被提到,我之前也在我的一篇文章Screen Snapshots with Java’s Robot 中提到。

不出所料,一些 Java 集合类也在列在其中。包括 java.util.EnumSetEnumMap (参考我的文章The Sleek EnumMap and EnumSet), java.util.ArrayDeque (参考我的文章The Java SE 6 Deque), java.util.PriorityQueue,java.util.Arrays, 以及 java.util.Collections (参考我的文章 The Java Collections Class).

以我之见,java.lang.ClassLoader, java.util.ServiceLoaderjava.nio.file.FileVisitor 是 Reddit Java 话题中提到的更精心构思和特别的类。我们大部分的情况下都是用强引用(strong reference),但java.lang.ref.WeakReference (弱引用)和 java.lang.ref.SoftReference (软引用)也在讨论中被提到。

最后,我经常使用的一个类和一个方法分别是 BigDecimal 类(我的一边文章中顺便提到了该类: Caution: Double to BigDecimal in Java )和 System.nanoTime()

结论:

我喜欢列表中的很多类,也能想到一些其他的例子。特别的,我想 JDK7 中的 Objects 类也能称得上很有用但鲜为人知的一个类把。我同样同意其中一个评论的说法:“把 Google guava 库添加进来吧!”,我也写过 一些博文 关于 Guava

原文:http://marxsoftware.blogspot.com/

翻译自:http://www.javaworld.com/community/node/8335

简单封装 FMDB 操作 sqlite 的模板

FMDB是 Objective-C 上操作 Sqlite 的开源库,与原生的操作 sqlite 数据库相比,有以下几个优点:

  1. 操作方便、简单、代码优雅,易于维护;
  2. 线程安全,用着更放心,很少出现过锁死数据库文件以及 Crash 的现象。

FMDatabase 不是线程安全的,一个 FMDatabase 对象一定不能在多线程中使用,为了保证线程安全,可以在 FMDB 中采取下面两种方式:

  1. 每个线程都创建一个 FMDatabase 对象,使用之前打开连接,用完关闭销毁;
  2. 使用 FMDatabaseQueue 来保证线程安全,一个 FMDatabaseQueue 的对象可以在多线程中共享使用。

使用 FMDatabase 时,一般这样来做:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 创建一个 FMDatabase 的对象
FMDatabase *db = [FMDatabase databaseWithPath:@"/tmp/tmp.db"];
// 判断 db 是否打开,在使用之前一定要确保是打开的
if ([db open]) {
// 使用 FMDatabase 操作数据库
FMResultSet *s = [db executeQuery:@"SELECT * FROM myTable"];
while ([s next]) {
//retrieve values for each record
}

// 关闭
[db close];
}
db = nil;

上面的这段代码是使用 FMDatabase 操作数据库的一个典型的使用方式,可以看到,其实我们关注的只是使用它来对数据库进行增删改查的操作,却每次都要写这些打开和关闭的操作,代码也显得臃肿,bad smell。用过 Java 中著名的 Spring 框架的同学都记得里面对数据库操作提供了一个 Template 的机制,比如 JdbcTemplate、HibernateTemplate 等,使用回调函数非常优雅的分离了创建连接、关闭连接和使用数据库连接操作数据库,下面就来模拟这个实现。 首先做个抽象,在上面代码的真正的逻辑中,我们只要拿到 db 变量就能满足我们的需要了,那么我们就把这一块抽象出来,在这里我们使用 oc 里的 block 来实现回调功能:

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
// 创建一个工具类 TWFmdbUtil
@implementation TWFmdbUtil
+ (void) execSqlInFmdb:(void (^)(FMDatabase *db))block {
NSString *dbPath = @"dbpath"; //sqlite 数据库文件的路径
// 创建一个 FMDatabase 的对象
FMDatabase *db = [FMDatabase databaseWithPath:dbPath];
// 使用之前保证数据库是打开的
if ([db open]) {
@try {
block(db); // 调用 block 来回调实现具体的逻辑
}
@catch (NSException *exception) {
// 处理异常,也可以直接抛出,这样调用者就能捕获到异常信息
NSLog(@"TWFmdbUtil exec sql exception: %@", exception);
}
@finally {
[db close]; // 如果[db open] 就要保证能关闭
}
} else {
// 如果打开失败,则打印出错误信息
NSLog(@"db open failed, path:%@, errorMsg:%@", dbPath, [db lastError]);
}
db = nil;
}
@end

现在使用的时候就能够像下面这样来实现了:

1
2
3
4
5
6
7
[TWFmdbUtil execSqlInFmdb:^(FMDatabase *db) {
// 处理业务逻辑
FMResultSet *s = [db executeQuery:@"SELECT * FROM myTable"];
while ([s next]) {
//retrieve values for each record
}
}];

这样的代码看起来是不是优雅多了呢?我们无需关心数据库的创建和关闭操作,只需要关心我们的业务逻辑就可以了。

历史总是惊人的相似,FMDatabaseQueue 的使用就是采用这样的方式来处理的,来看一段 fmdb 主页上提供的一个例子:

1
2
3
4
5
6
7
8
9
10
11
FMDatabaseQueue *queue = [FMDatabaseQueue databaseQueueWithPath:aPath];
[queue inDatabase:^(FMDatabase *db) {
[db executeUpdate:@"INSERT INTO myTable VALUES (?)", [NSNumber numberWithInt:1]];
[db executeUpdate:@"INSERT INTO myTable VALUES (?)", [NSNumber numberWithInt:2]];
[db executeUpdate:@"INSERT INTO myTable VALUES (?)", [NSNumber numberWithInt:3]];

FMResultSet *rs = [db executeQuery:@"select * from foo"];
while ([rs next]) {
//...
}
}];

更多实例请移步 FMDB 在 GitHub 上的 主页 或者访问 @唐巧_boy 关于 FMDB 的 这篇文章

Have Fun!

Blog 从 Wordpress 迁移到 Jekyll

最初的 Blog 放在了 GAE 上,使用一个叫 B3log 的 Blog 程序,但是间歇性的被墙访问不了,或者就是打开页面很慢,用着纠结;然后打算自己搞个 VPS,于是乎在 42qu 上买了个 VPS,搭建了一个 WordPress,使用很方便,但是需要经常担心服务器哪天挂掉,或者被攻击,或者哪个模块出问题要跑到服务器上检查。而且 WordPress 的绝大多数功能我也用不着,我一般就是写点文字放点代码而已,再加上 Jekyll 也很热,就尝试了一下 Jekyll,发现这才是我想要的 Blog 形式,非常简单,页面也很简洁,写作方式也很 Geek。打算暂时用 Jekyll 来写东西。

初探 Java8 新特性之 lambda 表达式

Java8 带有 Lambda 表达式的预览版的 JDK 已经放出来了(地址在最下面),新特性有以下四个:

  1. Lambda 表达式(或称之为“闭包”或者“匿名函数”)

  2. 扩展的目标类型

  3. 方法和构造器引用

  4. 接口默认方法

本文先介绍一下 Java8 中很值得期待的 Lambda 表达式,Lambda 表达式,等同于大多说动态语言中常见的闭包、匿名函数的概念。其实这个概念并不是多么新鲜的技术,在 C 语言中的概念类似于一个函数指针,这个指针可以作为一个参数传递到另外一个函数中。由于 Java 是相对较为面向对象的语言,一个 Java 对象中可以包含属性和方法(函数),方法(函数)不能孤立于对象单独存在。这样就产生了一个问题,有时候需要把一个方法(函数)作为参数传到另外一个方法中的时候(比如回调功能),就需要创建一个包含这个方法的接口,传递的时候传递这个接口的实现类,一般是用匿名内部类的方式来。如下面代码,首先创建一个 Runnable 的接口,在构造 Thread 时,创建一个 Runnable 的匿名内部类作为参数:

1
2
3
4
5
new Thread(new Runnable() {  
public void run() {
System.out.println("hello");
}
}).start();
类似这种情况的还有 swing 中 button 等控件的监听器,如下面代码所示,创建该接口的一个匿名内部类实例作为参数传递到 button 的 addActionListener 方法中。
1
2
3
4
5
6
7
8
9
public interface ActionListener {   
void actionPerformed(ActionEvent e);
}

button.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
ui.dazzle(e.getModifiers());
}
});

这样的代码的缺点是有代码笨重,可读性差,不能引用外面的非 final 的变量等。lambda 表达式就是为了解决这类问题而诞生的。

在介绍 Java8 中的 Lambda 表达式之前,首先介绍一个概念叫“函数式接口”(functional interfaces)。对于任意一个 Java 接口,如果接口中只定义了唯一一个方法,那么这个接口就称之为“函数式接口”。比如 JDK 中的 ActionListener、Runnable、Comparator 等接口。

先来看一下 Java8 中的 lambda 表达式的使用示例:

创建一个线程:

1
new Thread(() -> {System.out.println("hello");}).start();

可以看到这段代码比上面创建线程的代码精简了很多,也有很好的可读性。 () -> {System.out.println(“hello”);} 就是传说中的 lambda 表达式,等同于上面的 new Runnable(),lambda 大体分为 3 部分:

1. 最前面的部分是一对括号,里面是参数,这里无参数,就是一对空括号

2. 中间的是 -> ,用来分割参数和 body 部分

3. 是 body 部分,可以是一个表达式或者一个语句块。如果是一个表达式,表达式的值会被作为返回值返回;如果是语句块,需要用 return 语句指定返回值。如下面这个 lambda 表达式接受一个整形的参数 a,返回 a 的平方

1
2
3
(int a) -> a^2   
// 等同于
(int a) -> {return a^2;}
继续看更多的例子:
1
2
3
4
5
(int x, int y) -> x + y  

() -> 42

(String s) -> { System.out.println(s); }
创建一个 FileFilter,文件过滤器:
1
FileFilter java = (File f) -> f.getName().endsWith(".java")

创建一个线程:

1
2
3
new Thread(() -> {  
//do sth here...
}).start()

创建一个 Callable:

1
Callable<String> c = () -> "done";

而且 lambda 表达式可以赋值给一个变量:

1
2
Comparator<String> c;  
c = (String s1, String s2) -> s1.compareToIgnoreCase(s2);
当然还可以作为方法的返回值:
1
2
3
4
5
public Runnable toDoLater() {  
return () -> {
System.out.println("later");
};
}
从上面可以看到,一个 lambda 表达式被作为一个接口类型对待,具体对应哪个接口,编译器会根据上下文环境推断出来,如下面的 lambda 表达式就表示一个 ActionListener.
1
ActionListener l = (ActionEvent e) -> ui.dazzle(e.getModifiers());
这有可能会造成一个表达式在不同的上下文中被作为不同的类型,如下面的这种情况,尽管两个表达式是相同的,上面的表达式被推断为 Callable 的类型,下面的会被推断为 PrivilegedAction 类型。
1
2
Callable<String> c = () -> "done";  
PrivilegedAction<String> a = () -> "done";
那么编译器是根据哪些因为决定一个表达式的类型呢?

如果一个表达式被推断为是 T 类型的,需要满足以下 4 个条件:

  1. T 是函数式接口类型(只声明唯一一个方法)
  2. 表达式和 T 中声明的方法的参数个数一致,参数类型也一致
  3. 表达式和 T 中声明的方法的返回值类型一致
  4. 表达式和 T 中声明的方法抛出的异常一致 有了这个准则,上面的疑问就迎刃而解了

参考:

1.State of the Lambda

2.Java8 带有 Lambda 表达式版本的 JDK 下载地址

Guava/Google Collections 教程

最近在 OSChina 上翻译版块有一个系列(共 4 篇)关于 Guava/Google Collections 库的文章,我也有幸翻译了一部分。Guava 的中文意思是番石榴,这个库的功能和名字一样诱人,很好很强大,使用起来也很方便,强烈推荐。 这几篇文章都是 2009 年写的,现在的 Guava 库应该已经更新了很多,不过对于了解 Guava 库还是 OK 的。

Guava 托管在 Google Code 上的地址在 这里,目前最新版本是 14.0

Git 命令备忘

使用 diff 查看文件更改信息

1
2
3
4
5
6
7
8
9
10
# 查看未暂存文件的变化(与最近一次的暂存 / 提交比较)
$ git diff
# 查看已暂存文件的变化(与最近一次提交比较)
$ git diff --cached
# 查看与版本库中任一版本的变化
$ git diff 3e4e
# 查看任意两个版本间的变化
$ git diff 3e4e 5d5a
# 具体到某个文件
$ git diff 3e4e 5d5a index.md

查看任意版本下的某个文件

1
2
# 查看某个版本下某个文件内容 
$ git show i5d5a index.md