十二 30

第一章

     Xcode需要运行在基于Intel的Leopard之后的Mac OS之上
     Cocoa Touch使用Objective-C 2.0
     编写iPhone应用程序的特别之处
          只有一个正在运行的程序
          只有一个窗口
          访问受限     沙盒
          有限的响应时间     按下Home后5秒内没完成清理,将被强制退出
          有限的屏幕大小     480*320
          有限的系统资源     内存不足时,应用程序会收到通知。如果不能及时释放内存,可能被强制退出
          缺少Cocoa工具     不支持垃圾收集
          新属性     定位、摄像、图片库和加速计
     本书内容
          2 Interface Builder基础
          3 基础交互
          4 基本控件
          5 方向感应
          6 多视图
          7 工具栏
          8 TableView
          9 分层列表
          10 应用程序设置
          11 数据管理     SQLite
          12 绘图     Quartz和OpenGL ES
          13 多点触摸
          14 Core Location
          15 加速计
          16 摄像头和图片库
          17 I18n

第二章
     Project的目录结构,仅为逻辑结构
          Classes     存放大部分代码
          Other Sources     其他源代码
               .pch     预编译的头文件 precompiled header
               main.m     main函数,通常不需修改
          Resources     非代码文件,图标、图像、音频、视频文本
               .xib     Interface Builder用到的信息
               Info.plist     应用程序相关属性列表
               MainWindow.xib     主Interface Builder文件
          Frameworks     框架和库
          Products     编译生成的应用程序
     Interface Builder
          支持.nib(旧)和.xib(新)两种格式,统称nib或nib文件
     nib文件的构成
          File’s Owner     所有nib文件的第一个图标,表示加载nib文件的对象,控制器类是与之同名的nib文件的Owner
          First Responder     用户当前正在与之交互的对象,随用户与界面的交互而变化
          其他图标表示将在nib文件加载时创建的对象实例
     图标
          png     57*57
          放到Resources文件夹中
          在Info.plist中设置
     仿真器
          删除~/Library/Application Support/iPhone Simulator以清空主屏幕图标

第三章
     MVC模型
          M     Objective-C类
          V     Interface Builder
          C     NSObject,更多的是通用控制器类,如UIViewController
     控制器
          控制器类试用一种特殊的实例变量(输出口,outlet)来引用nib中的对象
          输出口可以看成是指向nib中的对象的指针
          可以通过绑定操作方法,设置nib文件的界面对象触发控制类中的特殊方法
     输出口
          IBOutlet     一个没有内容的宏,唯一作用是告诉Interface Builder此实例变量将被连接到nib中的对象
     操作
          IBAction     告诉Interface Builder,此方法是一个操作,且可以被某控件触发
          - (IBAction)doSomething:(id) sender;
     Outlet与Action的声明
          @property (retain, nonatomic) IBOutlet UILabel *statusText;
          retain 对象在内存中驻留
          nonatomic 无须支持多线程?
          myVar = [someObj foo] 等价于 myVar = someObj.foo
          someObj.foo = myVar 等价于 [someObj setFoo:myVar]
     Outlet与Action的实现
          @synthesize statusText
          [statusText release] in dealloc(),照应retain
     应用程序委托
          每个iPhone应用程序有且仅有一个UIApplication实例,负责应用程序的运行循环以及处理各种应用程序级功能
     连接输出口
          Control+拖动,从File‘s Owner到相应的控件对象
     指定操作
          Touch Up Inside
          拖动,从Event到File‘s Owner
          

Tagged with:
十二 27

1. 头文件依然是.h
2. .cpp变成了.m
3. #import代替了#include,#import保证只会引用一次,相当于.h里的#ifndef #define #endif模式
4. 用@interface … @end来声明类,取代class ClassName{}
5. 用@implementation … @end来实现类
6. Data Members放在@interface ClassName : Parent{ … }中,默认权限为@protected,在ObjC里称为Instance Variables
7. Member Functions放在@interface ClassName: Parent{} … @end中,在ObjC里称为Instance Methods
8. Instance Methods的声明方式为:scope (returnType) methodName: (parameter1Type) parameter1Name;
9. scope分instance和class两种,分别用-和+表示
10. 调用method的方式是[object method],相当于object->method()
11. 带参数调用method的方式是[object method: parameter]
12. 没有Object,只有Pointer to Object
13. 通常的构造方式: Object * obj = [[Object alloc] init]
14. 析构的方式:[obj release]15.多参数method的声明方式: scope (returnType) methodName: (parameter1Type) parameter1Name label1Name: (parameter2Type) parameter2Name … ;
16. labelName不是必须的
17. 这种特别的语法源自SmallTalk
18. private: [list of vars] protected: [list of vars] public: [list of vars] 改成了@private, @protected, @public
19. Class Variable用static的方法实现⋯⋯
20. +(void) initialize 会在构造的时候被调用
21. ObjC通常用@符号表示语言的衍生部分
22. ObjC用id来表示范型对象的指针
23. 支持动态类型识别
24. Categories机制可用于不继承已有class的前提下加入新功能
25. Posing机制允许Child取代Parent
26. Protocol相当于pure virtual class
27. ObjC由两种内存管理的方法,1) retain and release,2) retain and release/autorelease
28. Foundation相当于STL,NSArray对应vector,NSDictionary对应map
29. ObjC不支持Namespace
30. 不支持重载

Tagged with:
十二 05

用了JQuery,实在很方便。
但是很奇怪,评论小数字的click只有在展开了之后才会响应,路过的JS高手帮忙解释一下啊:)
已经上传到userscript.org,id63440,希望可以尽快修正上面提到的问题。

// ==UserScript==
// @name           QQMail Broadcast
// @namespace      QMBC
// @description    UI & Functional Improvement for Broadcast
// @include        http://*.mail.qq.com/cgi-bin/reader_article_list*
// ==/UserScript==
 
// Add jQuery
var GM_JQ = document.createElement('script');
GM_JQ.src = 'http://jquery.com/src/jquery-latest.js';
GM_JQ.type = 'text/javascript';
document.getElementsByTagName('head')[0].appendChild(GM_JQ);
 
// Check if jQuery's loaded
function GM_wait()
{
    if(typeof unsafeWindow.jQuery == 'undefined') { window.setTimeout(GM_wait,100); }
    else { $ = unsafeWindow.jQuery; letsJQuery(); }
}
GM_wait();
 
function letsJQuery()
{
    $(document).ready(function () {
		var _div = $("<div style='float: right;'></div>");
 
		var _readMode = $("<a>Read Mode</a>");
		_readMode.bind("click", ReadMode);
 
		_div.append(_readMode);
 
		$("<span>|</span>").css("margin", "10px").appendTo(_div);
 
		var _commentMode = $("<a>Comment Mode</a>");
		_commentMode.bind("click", CommentMode);
 
		_div.append(_commentMode);
 
		$("#articlecontent").prepend(_div);
    });
}
 
function ReadMode()
{
	$("div.update a[id^=artTitle_]").click();
}
 
function CommentMode()
{
	var links = $("div.postInfo a[id^=artCommentListLink]:visible");
	links.click();
}
Tagged with:
24

1. Hidden iframe

将iframe的src指向一个url,server收到请求后,Keep-Alive。
数据直接以script的方式下发到Browser,Browser收到数据后直接执行。
只要不超时,链接会一直保留。

优:感觉这是真正的长连接,对stream也有完整的支持。
劣:Browser状态栏会一直处于“连接中”,ESC会导致链接断开,会有跨域问题

2. Script Tag

用JS创建一个script对象,将该对象的src指向一个url,Keep-Alive。
在一定时间内(超时前),如果sever有数据下发,则用script的方式发送到Browser。
Browser收到数据后直接执行,此时需要重建script对象,建立另一个链接。

优:没有Hidden iframe的缺点,也比较轻量
劣:不是真正的长链接,每收到一个新的下发数据,都需要重新建立链接

3 AJAX

用JS创建一个XHR对象,将该对象的src指向一个url,Keep-Alive。
在一定时间内(超时前),如果sever有数据下发,则通过已建立的链接发送到Browser。
Browser收到数据后直接执行,此时需要重建XHR对象,建立另一个链接。

优:没有Hidden iframe的缺点
劣:存在跨域问题,不是真正的长链接,每收到一个新的下发数据,都需要重新建立链接

2 和 3也可以叫做Long Polling

除了这三种方法,还可以用Flash,由Flash和Server通信,页面用过JS和Flash通信。
这可以实现真正的下发,甚至不需要维护长链接。
但也可能存在被防火墙屏蔽的问题。

三种方法都用php模拟了一下:

Hidden Iframe

<html>
<head>
<script>
function callback(data)
{
	document.getElementById("t").value = data + "\n" + document.getElementById("t").value;
}
 
callback("abc");
</script>
</head>
<body>
hello
<textarea id="t"></textarea>
<iframe src="/hiddeniframe.php" width="0" height="0"></iframe>
</body>
</html>
<?php
	ob_end_flush();
	echo "<script>";
	echo "domain=serverpush";
	echo "</script>";
	for( ; ; )
	{
		$t = time();
		echo "<script>";
		echo "parent.callback($t);";
		echo "</script>";
		flush();
		sleep(1);
	}
?>

Script Tag

<html>
<head>
<script>
function callback(data)
{
	document.getElementById("t").value = data + "\n" + document.getElementById("t").value;
}
 
function connect()
{
    var _script = document.createElement("script");
    _script.setAttribute("type", "text/javascript");
    _script.setAttribute("src", "script.php");
    document.getElementsByTagName("head")[0].appendChild(_script);	
}
 
connect();
</script>
</head>
<body>
<textarea id="t"></textarea>
</body>
</html>
<?php
	sleep(10);
	$r = time();
	echo "callback($r);";
	echo "setTimeout(connect, 1000)";
?>

AJAX

<html>
<head>
<script>
function callback(data)
{
	document.getElementById("t").value = data + "\n" + document.getElementById("t").value;
}
 
function connect()
{
	var ajax = new XMLHttpRequest;
	ajax.open("POST", "ajax.php");
	ajax.onreadystatechange = function()
	{       
		if (ajax.readyState == 4)
		{       
			if (ajax.status == 200) 
			{       
				callback(ajax.responseText);	
				setTimeout(connect, 1000);
			}       
		}       
	}
	ajax.send();
}
 
connect();
 
</script>
</head>
<body>
<textarea id="t"></textarea>
</body>
</html>
<?php
	sleep(10);
	echo time();
?>
Tagged with:
18

昨晚看设计模式,顺便复习UML。
这里是一个比较好的图例说明,其中有些错误,于是用visio重画了一下。
美中不足的是,似乎visio不支持带箭头的Association,也可能是我不会用吧。

UML

Tagged with:
18

Google到CSDN上的结果:

在Visio图形元素上,点击右键,选择“形状显示选项”,将“实现链接”选中,这个时候,类图形元素上会出现一个黄点,拖动这个黄点,连接到表示接口的图形元素上。实现类和接口之间的关系就自动出来了。

Tagged with:
12

花了半天时间,看了一次http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html

下面是相关的笔记和理解,
感觉很多Status Code在实际的BS通信中都不常见,
更多像是为了定义完备的协议语义,
而这些语义现在已经部分由更上层的协议或者应用实现。

1xx Informational

100 Continue
    如果server可能拒绝request,则client只发送header部分,试探server的反应
    如果server接受,则返回100,于是client再发送剩余的body部分
101 Switch Protocol

2xx Successful

200 OK
201 Created

    有资源因Request而产生
202 Accepted
    Request要求的动作已经被记录,但真正的动作要等待若干时间才执行,而且不保证一定执行
203 Non-Authoritative Information
204 No Content

    google.cn的web server会返回
205 Reset Content
206 Partial Content

    用于断点续传,起始位置由Range指定。(可以参考迅雷的输出)

3xx Redirection

    User Agent需要处理循环的问题
300 Multiple Choices
    目标已变,有若干个替代品可供选择
301 Moved Permanently
    目标URI在Location里定义,除了HEAD和GET请求外,不能自动重定向
    对SEO不会有负面作用
302 Found
    临时重定向,是否用Moved Temporarily这个名字比较合适?
    目标URI在Location里定义,除了HEAD和GET请求外,不能自动重定向
    对SEO有负面作用
303 See Other
    和302类似,但期待User Agent用GET来请求Location里指定的URI
304 Not Modified
    通常Request会带If-Modified-Since
    不能带message-body
305 Use Proxy
    期待User Agent会使用Location中指定的Proxy地址,来访问数据
    只能由origin server产生
306 (not used)
    之前的版本用过,已经废弃,作为保留字
307 Temporary Redirect
    没看出和302有什么不同
    只有HTTP/1.1支持

4xx Client Error

    在message-body中,可以自定义给User的提示
400 Bad Request
    server不能理解Request的格式
    用telnet可以很容易模拟
401 Unauthorized
    不能通过HTTP Authentication
    response header必须包含WWW-Authoricate,request header可能包含Authorization
402 Payment Required
    保留字
403 Forbidden
    如果不希望暴露过多的信息,可以用404代替
404 Not Found
    最常见的4字头Status Code,通常会自定义
405 Method Not Allowed
    response header需要包含Allow,列出支持的method
406 Not Acceptable
    response不被request header中的Accept做支持
    除了HEAD,response会给出包含更多信息的entity
    entity format由request header中的Content-Type决定
407 Proxy Authentication Required
    与401类似
    Proxy的response header必须包含Proxy-Authenticate
408 Request Timeout
409 Conflict

    需要User干预解决
    在PUT的时候可能遇到
410 Gone
    URI已经不存在,且不提供3xx来重定向
    如果server没有足够的信息来判断URI的不存在是temporary还是permanent,可以用404代替
411 Length Required
    request header中缺少Content-Length
412 Precondition Failed
413 Request Entity Too Large

    如果只是temporary,可以包含Retry-After,指定重试的时间间隔
414 Request-URI Too Long
    有几种可能导致这个返回码的情况
    将POST当成了GET
    循环重定向,每次都append上当前URI
    攻击
415 Unsupported Media Type
    416 Requested Range Not Satisfiable

    参考206
417 Expectation Failed
    不能满足request header中的Expect,参考100

5xx Server Error

500 Internal Server Error
    在server没有输出正确的response header的时候会出现
501 Not Implemented
502 Bad Gateway

    由gateway或者proxy返回,表明上游server不能返回请求的URI
503 Service Unavailable
    server可能过载,或者正在维护
    可以返回Retry-After,如果没有,则视作500
504 Gateway Timeout
    上游server不能及时返回
505 HTTP Version Not Supported

Tagged with:
11

实在很简陋,许多控制功能都没有实现:)
不过也能表现大致的框架吧。

/*
 * A simple process pool
 */
#include <iostream>
#include <queue>
#include <vector>
#include <algorithm>
 
#include <sys/wait.h>
#include <assert.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
 
#include <sys/mman.h>
#include <sys/select.h>
 
using namespace std;
 
int iProcessCount = 0;
int *pDispatchCount;
 
void InterruptHanler(int iSigno)
{
	//ToDo: kill all children
	cerr << "Dispatch Count: " << endl;
	for( unsigned int i = 0; i < iProcessCount; i++ )
	{
		cerr << i << "\t" << pDispatchCount[i] << endl;
	}
	exit(0);
}
 
//ToDo: replace two pipes with socketpair
int main(int argc, char **argv)
{
	if( argc == 2 )
	{
		iProcessCount = atoi(argv[1]);
	}
 
	if( iProcessCount <= 0 )
		iProcessCount = 10;
 
	int (*iPipeFD)[2] = new(int[iProcessCount][2]);
	int (*iNotifyPipeFD)[2] = new(int[iProcessCount][2]);;
	pDispatchCount = (int *)mmap(0, sizeof(int) * iProcessCount, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);
 
	queue<int> queIdle;
	vector<int> vecBusy;
 
	for( unsigned int i = 0; i < iProcessCount; i++ )
	{
		if( pipe(iPipeFD[i]) == -1 )
		{
			cerr << "pipe error" << endl;
			return 0;	
		}
 
		if( pipe(iNotifyPipeFD[i]) == -1 )
		{
			cerr << "pipe error" << endl;
			return 0;	
		}
	}
 
	for( unsigned int i = 0; i < iProcessCount; i++ )
	{
		pid_t pid = fork();
		if( pid < 0 )
		{
			cerr << "fork error" << endl;
			return 0;
		}
 
		if( pid == 0 )	//child
		{
			int iCount = 0;
			while(1)
			{
				char sBuf[16] = {0};
				read( iPipeFD[i][0], sBuf, 15 );
				cout << i << ": " << getpid() << ", " << ++iCount << "\t" << sBuf << endl;
				pDispatchCount[i]++;
 
				//Do your work here
				int iMax = atoi(sBuf);
				usleep(iMax % 10000);
 
				write( iNotifyPipeFD[i][1], "1", 1);
			}
		}
 
		queIdle.push(i);
	}
 
	signal( SIGINT, InterruptHanler );
 
	int iCounter = 0;
	while( 1 ) 
	{
		if( queIdle.size() )
		{
			//Dispatch work
			char sBuf[16] = {0};
			int iRand = rand();
			snprintf(sBuf, 16, "%d", iRand);
 
			int iIndex = queIdle.front();
			queIdle.pop();
			write( iPipeFD[iIndex][1], sBuf, strlen(sBuf) );
			cout << "dispatch " << sBuf << " to " << iIndex << endl;
 
			vecBusy.push_back(iIndex);
		}
 
		cout << ++iCounter << "\t: queIdle.size = " << queIdle.size() << " vecBusy.size = " << vecBusy.size() << endl;
		//if( vecBusy.size() )
		{
			fd_set set;
			FD_ZERO(&set);
 
			int iMaxFD = 0;	
			for( unsigned int i = 0; i < vecBusy.size(); i++ )
			{
				int iIndex = vecBusy[i];
				FD_SET( iNotifyPipeFD[iIndex][0], &set);
				iMaxFD = max( iMaxFD, iNotifyPipeFD[iIndex][0]);
			}
 
			struct timeval timeout;
			timeout.tv_sec = 1;
			timeout.tv_usec = 0;
			select(iMaxFD + 1, &set, NULL, NULL, &timeout);
 
			for( vector<int>::iterator it = vecBusy.begin(); it != vecBusy.end(); )
			{
				int iIndex = *it;
				int iReadFD = iNotifyPipeFD[iIndex][0];
				if( FD_ISSET( iReadFD, &set ) )
				{
					queIdle.push(iIndex);
					it = vecBusy.erase(it);
				}
				else
				{
					it++;
				}
			}
		}
	}
 
	return 0;
}
18

重构是最近想得比较多的一个词。
星期一去总部培训,其中一门课叫做《边重构边生活》,提到很多关于重构的意识。
对其中一个说法印象尤为深刻:火箭发射式的重构

火箭发射是一件相当隆重的大事,
需要经过长时间的准备,花费不计其数的人力物力后,
在一个精心选择的时间,所有相关人物齐聚一堂,等待火箭的轰然升空。

最大的问题是,火箭发射可能失败,在付出巨大的努力后,依然失败。

个中的情形与后果,与软件开发中的一次性重构非常相似。

一次性重构是软件开发中一种相当具有冒险精神的活动,
需要实施者有“不成功便成人”的坚毅决心,埋头苦干若干日子,
最后在合十祈祷中,迎来一个充满不确定因素的发布。
用Bison的话来说,是找死。

找死也有两种找法,
一种是终止老版本,不接新需求,专心闭门造车,重写一个新版本;
还有一种是同时维护两个版本,老版本做新需求,等新版本做出来之后,再把新功能合并过去。
前一种伴随着巨大的风险,而后一种则会带来太多额外的复杂性,都不是一个理性程序员的选择。

更好的方式是采用平滑重构,这才是真正意义上的重构。
只要不是病入膏肓,这是最佳选择。

由此想到一个不太恰当的比喻:将编写程序比喻为治理国家。

假如现在的执政党已经日益腐朽,人浮于事,贪污横行。
总之,是到了需要改革(重构)的时候了。
此时有两个选择:革命,或者重新大选。
先不论大选的利弊,单看革命。
另一股势力,利用民众的不满,积极宣称自己的主义可以拯救这个岌岌可危的国家;
由于拥戴者渐多,力量日益强大,终于到了可以和执政者分庭抗礼的程度。
执政者当然不会轻易交出自己手中的权力,
于是经过非常暴力或者不太暴力(没有非暴力这个选择)的斗争,
新势力终于推翻了旧势力,春风得意的上台了。
一时间,气象一新,处处欣欣向荣的美好景象。
经过若干年后,执政党开始日益腐朽,人浮于事,贪污横行。
又一个轮回开始了⋯⋯

这种情形,历史上还少见吗?
软件终究会腐朽的,就像政党一样。
与其暴风骤雨,我宁可润物无声。

Tagged with:
15

偶尔发现了一个不错的Mac风格主题,可以把原来的Win7换掉了:)

icomes.net_macicomes.net_win7

Tagged with:
preload preload preload