C#中让WebBrowser运行Javascript脚本

C#中可以让Webbrowser运行Javascript脚本来实现各种自动化操作,比如点击网页上的按钮,输入用户名密码等等。代码也很简单:

>>>>>>>>>>>>>>>>>>>>方法一:
只需要先获取HtmlElement,然后对获取的element进行操作即可,比如:

  1.             HtmlElement btn = webBrowser1.Document.GetElementById(“aBtn”);
  2.             if (btn != null)
  3.                 btn.InvokeMember(“click”);

>>>>>>>>>>>>>>>>>>>>方法二:
给页面注入javascript代码:

  1. HtmlElement ele = webBrowser1.Document.CreateElement(“script”);
  2. ele.SetAttribute(“type”, “text/javascript”);
  3. ele.SetAttribute(“text”, “someJavaScript”);
  4. webBrowser1.Document.Body.AppendChild(ele);

最后一句话执行之后会自动执行javascript

>>>>>>>>>>>>>>>>>>>>方法三:
运行页面中已经有的脚本:

  1. webBrowser1.Document.InvokeScript(“someInPageJavaFunction”, null);

>>>>>>>>>>>>>>>>>>>>另外:
另外webbrowser中加载网页,如果遇到脚本错误的话,默认会弹出对话框,这有时候比较烦人,不过可以关闭之:

  1. webbrowser.ScriptErrorsSuppressed = true;

iOS开发中使用NSOperationQueue进行多线程操作

NSOperationQueue是iOS的SDK中提供的一个非常方便的多线程机制,用它来开发多线程非常简单。

可以把它视为一个线程池,还可以调用方法
-(void)setMaxConcurrentOperationCount:maxConcurrentNumber
来设置它的并行程度,默认为-1,即最大并行。

还可以通过NSOperation的方法来指定并行的操作之间的依赖关系:

  1. [theLatterTask addDependency:theBeforeTask];

在一个队列之中,可以加入NSOperation来指定执行的任务:
1.可以重载NSOperation的main方法来指定操作;
2.可以使用NSInvokeOperation通过指定selector和target来指定操作;
3.可以使用NSBlockedOperation通过Block来指定操作
这三个方法都非常方便。

以下是一个例子:

  1. _tasksQueue=[[NSOperationQueue alloc] init]; 
  2.     
  3. NSBlockOperation *getImageTask = [NSBlockOperation blockOperationWithBlock:^{
  4.         UIImage * image = nil;
  5.         NSData *imgData = [NSURLConnection sendSynchronousRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:imageUrl]] returningResponse:nil error:nil];
  6.         if (imgData >> imgData.length > 0) {
  7.             image = [UIImage imageWithData:imgData];
  8.         }
  9.     }];
  10.  
  11. [_tasksQueue addOperation:getImageTask];

iOS (objective-c) 中的多线程互斥同步问题

在iOS中有几种方法来解决多线程访问同一个内存地址的互斥同步问题:

方法一,@synchronized(id anObject),(最简单的方法)

会自动对参数对象加锁,保证临界区内的代码线程安全

  1. @synchronized(self) {
  2.         // 这段代码对其他 @synchronized(self) 都是互斥的
  3.         // self 指向同一个对象
  4. }

方法二,NSLock

NSLock对象实现了NSLocking protocol,包含几个方法:
lock,加锁
unlock,解锁
tryLock,尝试加锁,如果失败了,并不会阻塞线程,只是立即返回NO
lockBeforeDate:,在指定的date之前暂时阻塞线程(如果没有获取锁的话),如果到期还没有获取锁,则线程被唤醒,函数立即返回NO
比如:

  1. NSLock *theLock = [[NSLock alloc] init]; 
  2.  if ([theLock lock]) {
  3.     //do something here
  4.     [theLock unlock]; 
  5. } 

方法三,NSRecursiveLock,递归锁

NSRecursiveLock,多次调用不会阻塞已获取该锁的线程。

  1. NSRecursiveLock *theLock = [[NSRecursiveLock alloc] init]; 
  2. void MyRecursiveFunction(int value) { 
  3.     [theLock lock]; 
  4.     if (value != 0) { 
  5.         value; 
  6.         MyRecursiveFunction(value); 
  7.     }
  8.     [theLock unlock]; 
  9. } 
  10. MyRecursiveFunction(5);

方法四,NSConditionLock,条件锁

NSConditionLock,条件锁,可以设置条件

  1. //公共部分
  2. id condLock = [[NSConditionLock alloc] initWithCondition:NO_DATA]; 
  3.  
  4. //线程一,生产者
  5. while(true) { 
  6.     [condLock lockWhenCondition:NO_DATA]; 
  7.     //生产数据
  8.     [condLock unlockWithCondition:HAS_DATA]; 
  9. }
  10.  
  11. //线程二,消费者
  12. while (true) { 
  13.     [condLock lockWhenCondition:HAS_DATA]; 
  14.     //消费
  15.     [condLock unlockWithCondition:NO_DATA]; 
  16. }

方法五,NSDistributedLock,分布锁

NSDistributedLock,分布锁,文件方式实现,可以跨进程
用tryLock方法获取锁。
用unlock方法释放锁。
如果一个获取锁的进程在释放锁之前挂了,那么锁就一直得不到释放了,此时可以通过breakLock强行获取锁。

参考:

http://blog.sina.com.cn/s/blog_72819b170101590n.html

iOS (objective-c) 中的异常处理

objective-c中的异常处理很简单,经典的try,catch,final。需要注意的是,只能抛出NSObject对象。在cache块中还能继续用@throw进一步向外抛出异常。

  1. @try {
  2.     dangerousAction();
  3. } @catch (MyException* e) {
  4.     doSomething();
  5. } @catch (NSException* e) {
  6.     doSomethingElse();
  7.     @throw // 重新抛出异常
  8. } @finally {
  9.     cleanup();
  10. }

参考:
http://www.devbean.info/2011/04/from_cpp_to_objc_17/

从短url获取正常url(php,objective-c ios)

微博的兴起将很多长的url转换成了短url地址,但是有时候我们需要先通过短url拿到长url,再进行进一步的处理。

ios方法

  1. +(NSString*)unshortUrl🙁NSString*)shortUrl{
  2.     shortUrl = @“http://rrurl.cn/xxoo”;
  3.     NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:shortUrl]];
  4.     NSHTTPURLResponse *response = [[[NSHTTPURLResponse alloc] init] autorelease];
  5.     [NSURLConnection sendSynchronousRequest:request returningResponse:>response error:nil];
  6.     return response.URL.absoluteString;
  7. }

php方法

  1. $url = “http://rrurl.cn/xxoo”; 
  2. echo unshorten($url); 
  3. function unshorten($url) { 
  4. $url = trim($url); 
  5. $headers = get_headers($url); 
  6. $location = $url; 
  7. $short = false; 
  8. foreach($headers as $head) { 
  9. if($head==“HTTP/1.1 302 Found”) $short = true; 
  10. if($short >> startwith($head,“Location: “)) { 
  11. $location = substr($head,10); 
  12. } 
  13. } 
  14. return $location; 
  15. } 

UIWebView背景透明的方法

想要UIWebView的背景透明,需要以下3步:

step1.设置webview的opaque=NO

step2.设置webview的backgroundColor = [UIColor clearColor];

step3.加载这样的内容到webView:

  1. <html><body style=“backgroundcolor:transparent;color:#ffffff”>具体内容</body></html>

传照片到iPhone,通过iFunbox

用iFunbox可以传照片到iPhone上的DCIM目录下,但是当打开“照片”app的时候,是看不见的。
要看见这些照片,需要删除两个文件,然后照片程序会自动重建,之后就能看见上传的照片了。这两个文件是:
var/mobile/Media/photoData目录下的“photos.sqlite和photosAux.sqlite”



2013-2-15 更新
在iOS 5.1 系统上,估计之后也是,只需要删除photos.sqlite就好了。

删除之后,把“照片”应用彻底结束掉(在多任务栏点叉叉),然后重新打开它。别被一开始的“没有照片”吓到了,等几秒之后它会开始重建数据库,之后就能看到新拷贝进去的照片了。

关于人人开放平台中的Like.like接口

人人开放平台的Like.like接口,是用于标记用户喜欢的内容,相当于新浪微博的收藏。
发现这个接口总返回成功,确没有“喜欢”成功。
在调试了很久以后,终于发现它的规律:
主要是其url参数:其中需要的是resourceId,ownerID,type,这中间大有猫腻(再次不得不说一下人人的api之混乱)

对于share类型的
包括日志share(代码21),相册share(代码33)需要传送的是source_id,actor_id和@”share”

对于上传照片(30)类型
需要传送的是attachement下的meida_id,owner_id和media_type

对于发布日志(20)类型
需要传送的是source_id,actor_id和@”blog”

这样才能“喜欢”成功,刷新“首页”或者“个人主页”可以看到效果,但是要在”喜欢列表“里面看到内容的话,貌似需要一天以后···额···并且人人没有提供获取这个列表的api···

php操作mysql数据库

在采用了php和mysql作为开发服务器端工具之后,首先就是怎么在php中去读取,修改数据库中的数据。
php内置了很多以mysql_开头的函数来进行mysql数据库的操作,非常方便。这里用一个例子来说明常用函数的使用吧。

以feedback功能为例,设计一个数据库表格,有以下字段
fbID,fbContent,fbEmail,fbName,fbTime

首先用户通过http post方法进行一次反馈操作,那么遇到的数据库操作就有:打开数据库连接,选择数据库,执行insert语句,断开数据库。即:
1.连接数据库
$db = @mysql_connect('localhost','dbusername','dbpassword') or die('db connect error');
2.选择数据库
@mysql_select_db('testapi',$db) or die('db select error');
3.执行insert查询语句将数据插入数据库
$sqlInsert = "insert into feedbacks (fbContent,fbEmail,fbName,fbTime) value ('".$feedBackArray['content']."','".$feedBackArray['email']."','".$feedBackArray['name']."','".$feedBackArray['time']."')";
@mysql_query($sqlInsert,$db) or die('db insert error');

4.断开数据库连接
mysql_close($db);
以上就是在php中插入数据到mysql数据库中的一个方法,对其中的insert语句做一些变化,也就实现了各种对数据库的操作了。

接下来的另一个方面是如何从mysql中查询数据,以及如何使用查询得到的数据。其中连接数据库,选择数据库,断开连接同上,只是第三步有说区别:

  1. $fbResultsFromDB = @mysql_query ( ‘select * from feedbacks’, $db ) or die ( ‘db select error’ );
  2. $row = mysql_fetch_row ( $fbResultsFromDB );
  3. echo ‘<table><tr><td>ID</td><td>Content</td><td>Email</td><td>Name</td><td>GMTTime</td></tr>’;
  4. while ( ! empty ( $row ) ) {
  5.     echo “<tr>”;
  6.     echo “<td>” . $row [0] . “</td>”;
  7.     echo “<td>” . $row [1] . “</td>”;
  8.     echo “<td>” . $row [2] . “</td>”;
  9.     echo “<td>” . $row [3] . “</td>”;
  10.     echo “<td>” . $row [4] . “</td>”;
  11.     echo ‘</tr>’;
  12.     $row = mysql_fetch_row ( $fbResultsFromDB );
  13. }
  14. echo ‘</table>’;
  15. mysql_free_result ( $fbResultsFromDB );

使用mysql_query函数来得到查询结果,对查询结果不断调用mysql_fetch_row方法来获取每一行的数据,得到的数据是一个array。以上代码片段是将查询到的数据以表格形式打印在浏览器上。

第一次写Apache2的RewriteRule(用于域名泛解析)

在研究了正则表达式和apache的rewrite模块之后,写了第一个rewriterule,实现的功能是:
将所有的对:
name1.name2.dom.com/someResource
的访问都定向到服务器目录:
/server/name2/name1/someResource
其中name1和someResource是可变部分。对于name1,相当于实现了三级域名的泛解析。

那么在VirtualHost块下是这么写的:
//打开重写模块,这个的好处在于不需要重写的的时候,只把on改成off就让下面的代码全部失效了,不用一句一句注释
RewriteEngine on
//判断继续下一步的条件是请求的url的服务器部分(http://之后到第一个/之前,变量名是%{HTTP_HOST})
//是不是长得像name1.name2.dom.com

RewriteCond %{HTTP_HOST} ^[^.]+.name2.dom.com$
//重写访问的地址,将"/someResource"改为:"name1.name2.dom.com/someResource"
RewriteRule ^(.+) %{HTTP_HOST}$1 [C]
//再重写一次,将"name1.name2.dom.com/someResource",改写为"/server/name2/name1/someResource"
//其中每个()匹配的字符串都可以用$1这样的变量名来引用,()的定义是从左到右编号的(从1开始)
//第一个()是:([^.]+),在这里匹配的是"name1"字符串,也就相当于$1="name1"
//第二个()是:(.),在这里匹配的是"/someSource",也就相当于$2="/someSource"
//所以重写的结果"/server/name2/$1$2"翻译出来就是"/server/name2/name1/someSource"。也就是我们的目标地址

RewriteRule ^([^.]+).name2.dom.com(.
) /server/name2/$1$2

正则表达式

想学正则表达式很久了,今天终于看了看。因为在apache中的rewrite中需要用正则表达式去匹配url。
后面链接的一篇文章讲得很详细了,就不复制粘贴了,以后有学习心得之类的再补充在此。

一篇好文章可以看看:
http://manual.phpv.net/regular_expression.htmlX128X
另外一个来自百度百科的条目,其中有正则表达式各个字符的含义
正则表达式字符含义在此

在objective-c中使用的方式如下:(这个例子检测文本text中的url)

  1.     NSString *text = [info objectForKey:@“text”];
  2.     NSString *urlDetected = nil;
  3.     {//url detection
  4.         //if there is a link of this feed, such as video share, the text is like:@”sometexthttp://somelocation”. And the url link is only contained in this text.
  5.         NSRegularExpression *regExp = [NSRegularExpression regularExpressionWithPattern:@“(http|https|ftp)\\://([a-zA-Z0-9\\.\\-]+(\\:[a-zA-Z0-9\\.>amp;%\\$\\-]+)*@)?((25[0-5]|2[0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[1-9])\\.(25[0-5]|2[0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[1-9]|0)\\.(25[0-5]|2[0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[1-9]|0)\\.(25[0-5]|2[0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[0-9])|([a-zA-Z0-9\\-]+\\.)*[a-zA-Z0-9\\-]+\\.[a-zA-Z]{2,4})(\\:[0-9]+)?(/[^/][a-zA-Z0-9\\.\\,\\?\\’\\\\/\\+>amp;%\\$#\\=~_\\-@]*)*” options:NSRegularExpressionCaseInsensitive error:nil];
  6.         NSRange matchedUrlRange = [regExp rangeOfFirstMatchInString:text options:0 range:NSMakeRange(0, text.length)];
  7.         if (matchedUrlRange.location != NSNotFound) {
  8.             urlDetected = [text substringWithRange:matchedUrlRange];
  9.         }
  10.     }

http中content-type对照表【转】

常见文件的http中content-type头的值(MIME类型)

An official listing of defined MIME types:

.ai - application/postscript
.aif - audio/x-aiff
.aifc - audio/x-aiff
.aiff - audio/x-aiff
.asc - text/plain
.au - audio/basic
.avi - video/x-msvideo
.bcpio - application/x-bcpio
.bin - application/octet-stream
.c - text/plain
.cc - text/plain
.ccad - application/clariscad
.cdf - application/x-netcdf
.class - application/octet-stream
.cpio - application/x-cpio
.cpt - application/mac-compactpro
.csh - application/x-csh
.css - text/css
.dcr - application/x-director
.dir - application/x-director
.dms - application/octet-stream
.doc - application/msword
.drw - application/drafting
.dvi - application/x-dvi
.dwg - application/acad
.dxf - application/dxf
.dxr - application/x-director
.eps - application/postscript
.etx - text/x-setext
.exe - application/octet-stream
.ez - application/andrew-inset
.f - text/plain
.f90 - text/plain
.fli - video/x-fli
.gif - image/gif
.gtar - application/x-gtar
.gz - application/x-gzip
.h - text/plain
.hdf - application/x-hdf
.hh - text/plain
.hqx - application/mac-binhex40
.htm - text/html
.html - text/html
.ice - x-conference/x-cooltalk
.ief - image/ief
.iges - model/iges
.igs - model/iges
.ips - application/x-ipscript
.ipx - application/x-ipix
.jpe - image/jpeg
.jpeg - image/jpeg
.jpg - image/jpeg
.js - application/x-javascript
.kar - audio/midi
.latex - application/x-latex
.lha - application/octet-stream
.lsp - application/x-lisp
.lzh - application/octet-stream
.m - text/plain
.man - application/x-troff-man
.me - application/x-troff-me
.mesh - model/mesh
.mid - audio/midi
.midi - audio/midi
.mif - application/vnd.mif
.mime - www/mime
.mov - video/quicktime
.movie - video/x-sgi-movie
.mp2 - audio/mpeg
.mp3 - audio/mpeg
.mpe - video/mpeg
.mpeg - video/mpeg
.mpg - video/mpeg
.mpga - audio/mpeg
.ms - application/x-troff-ms
.msh - model/mesh
.nc - application/x-netcdf
.oda - application/oda
.pbm - image/x-portable-bitmap
.pdb - chemical/x-pdb
.pdf - application/pdf
.pgm - image/x-portable-graymap
.pgn - application/x-chess-pgn
.png - image/png
.pnm - image/x-portable-anymap
.pot - application/mspowerpoint
.ppm - image/x-portable-pixmap
.pps - application/mspowerpoint
.ppt - application/mspowerpoint
.ppz - application/mspowerpoint
.pre - application/x-freelance
.prt - application/pro_eng
.ps - application/postscript
.qt - video/quicktime
.ra - audio/x-realaudio
.ram - audio/x-pn-realaudio
.ras - image/cmu-raster
.rgb - image/x-rgb
.rm - audio/x-pn-realaudio
.roff - application/x-troff
.rpm - audio/x-pn-realaudio-plugin
.rtf - text/rtf
.rtx - text/richtext
.scm - application/x-lotusscreencam
.set - application/set
.sgm - text/sgml
.sgml - text/sgml
.sh - application/x-sh
.shar - application/x-shar
.silo - model/mesh
.sit - application/x-stuffit
.skd - application/x-koan
.skm - application/x-koan
.skp - application/x-koan
.skt - application/x-koan
.smi - application/smil
.smil - application/smil
.snd - audio/basic
.sol - application/solids
.spl - application/x-futuresplash
.src - application/x-wais-source
.step - application/STEP
.stl - application/SLA
.stp - application/STEP
.sv4cpio - application/x-sv4cpio
.sv4crc - application/x-sv4crc
.swf - application/x-shockwave-flash
.t - application/x-troff
.tar - application/x-tar
.tcl - application/x-tcl
.tex - application/x-tex
.texi - application/x-texinfo
.texinfo - application/x-texinfo
.tif - image/tiff
.tiff - image/tiff
.tr - application/x-troff
.tsi - audio/TSP-audio
.tsp - application/dsptype
.tsv - text/tab-separated-values
.txt - text/plain
.unv - application/i-deas
.ustar - application/x-ustar
.vcd - application/x-cdlink
.vda - application/vda
.viv - video/vnd.vivo
.vivo - video/vnd.vivo
.vrml - model/vrml
.wav - audio/x-wav
.wrl - model/vrml
.xbm - image/x-xbitmap
.xlc - application/vnd.ms-excel
.xll - application/vnd.ms-excel
.xlm - application/vnd.ms-excel
.xls - application/vnd.ms-excel
.xlw - application/vnd.ms-excel
.xml - text/xml
.xpm - image/x-xpixmap
.xwd - image/x-xwindowdump
.xyz - chemical/x-pdb
.zip - application/zip

PHP文件操作

打开文件 <<<<<<<<<<<<<
$handle = fopen($filename, 'a');
mode说明
‘r’ 只读方式打开,将文件指针指向文件头。
‘r+’ 读写方式打开,将文件指针指向文件头。
‘w’ 写入方式打开,将文件指针指向文件头并将文件大小截为零。如果文件不存在则尝试创建之。
‘w+’ 读写方式打开,将文件指针指向文件头并将文件大小截为零。如果文件不存在则尝试创建之。
‘a’ 写入方式打开,将文件指针指向文件末尾。如果文件不存在则尝试创建之。
‘a+’ 读写方式打开,将文件指针指向文件末尾。如果文件不存在则尝试创建之。
‘x’ 创建并以写入方式打开,将文件指针指向文件头。如果文件已存在,则 fopen() 调用失败并返回 FALSE,并生成一条 E_WARNING 级别的错误信息。如果文件不存在则尝试创建之。这和给 底层的 open(2) 系统调用指定 O_EXCL|O_CREAT 标记是等价的。此选项被 PHP 4.3.2 以及以后的版本所支持,仅能用于本地文件。
‘x+’ 创建并以读写方式打开,将文件指针指向文件头。如果文件已存在,则 fopen() 调用失败并返回 FALSE,并生成一条 E_WARNING 级别的错误信息。如果文件不存在则尝试创建之。这和给 底层的 open(2) 系统调用指定 O_EXCL|O_CREAT 标记是等价的。此选项被 PHP 4.3.2 以及以后的版本所支持,仅能用于本地文件。
读取二进制文件最好加b标记,比如$handle = fopen($filename, 'ab');


>>>>>>>>>>>>>> 关闭文件 <<<<<<<<<<<<<
fclose($handle);


>>>>>>>>>>>>>> 读取文件 <<<<<<<<<<<<<
$char = fgetc($fp);//读取一个字符
string fgets ( int handle [, int length])//读取一行(最长到length,默认1K)


>>>>>>>>>>>>>> 写文件 <<<<<<<<<<<<<
int fwrite ( resource handle, string string [, int length])//最长写到length


>>>>>>>>>>>>>> 看一个简单的例子 <<<<<<<<<<<<<



参考:
http://www.php100.com/manual/php/

iOS开发中的键盘高度变化处理

在ios开发中,键盘很常用。在sdk版本5.0以前,键盘高度是固定值216px;5.0出来以后,键盘高度会随着键盘语言变化(中文要高些),在这种情况下一般而言对于界面需要重新布局。方法是利用NSNotificationCenter。

UIKeyboardWillShowNotification;
UIKeyboardDidShowNotification; 
UIKeyboardWillHideNotification; 
UIKeyboardDidHideNotification;

这几个notification是5.0sdk之前就有的,顾名思义就知道意思了。

UIKeyboardWillChangeFrameNotification  __OSX_AVAILABLE_STARTING(__MAC_NA,__IPHONE_5_0);
UIKeyboardDidChangeFrameNotification   __OSX_AVAILABLE_STARTING(__MAC_NA,__IPHONE_5_0);

这两个是sdk 5.0以后出来的,用来处理键盘高度的变化。

使用方法是:首先在notification注册观察者,比如:

if([[[UIDevice currentDevice] systemVersion] floatValue] >= 5.0) {
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillChangeFrame:) name:UIKeyboardWillChangeFrameNotification object:nil];
}

当键盘高度将要变化时,就会收到通知,在通知的参数中可以得到键盘目前的高度和变化的目标高度,比如:

-(void)keyboardWillChangeFrame:(NSNotification*)notif{
#if __IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_3_2  
    NSValue *keyboardBoundsValue = [[notif userInfo] objectForKey:UIKeyboardFrameEndUserInfoKey];  
#else  
    NSValue *keyboardBoundsValue = [[notif userInfo] objectForKey:UIKeyboardBoundsUserInfoKey];  
#endif
    CGRect keyboardEndRect = [keyboardBoundsValue CGRectValue];
    CGRect inputFrame = self.feedBackTextView.frame;
    //kb 216 vs textFrame 185
    float delta = keyboardEndRect.size.height - 216;
    float originalHeight = inputFrame.size.height;
    inputFrame.size.height = 185 - delta;
    if (inputFrame.size.height != originalHeight) {
        self.feedBackTextView.frame = inputFrame;
        self.feedBackBackgroundView.frame = inputFrame;
    }
}

另外一些从notification.userInfo中可以取得的key如下:

UIKeyboardFrameBeginUserInfoKey        // NSValue of CGRect
UIKeyboardFrameEndUserInfoKey          // NSValue of CGRect
UIKeyboardAnimationDurationUserInfoKey // NSNumber of double
UIKeyboardAnimationCurveUserInfoKey    // NSNumber of double



notif中userInfo的完整信息如下

keyboardChange:{
    UIKeyboardAnimationCurveUserInfoKey = 0;
    UIKeyboardAnimationDurationUserInfoKey = "0.25";
    UIKeyboardBoundsUserInfoKey = "NSRect: {{0, 0}, {320, 216}}";
    UIKeyboardCenterBeginUserInfoKey = "NSPoint: {160, 372}";
    UIKeyboardCenterEndUserInfoKey = "NSPoint: {160, 588}";
    UIKeyboardFrameBeginUserInfoKey = "NSRect: {{0, 264}, {320, 216}}";
    UIKeyboardFrameChangedByUserInteraction = 0;
    UIKeyboardFrameEndUserInfoKey = "NSRect: {{0, 480}, {320, 216}}";
}



下面是一个完整的解决方案,用户需要知道键盘高度的细致变化

#pragma mark Keyboard
-(void)keyboardWillChangeFrame:(NSNotification*)notif{
    NSLog(@"keyboardChange:%@",[notif userInfo]);
    float keyboadHeightBegin = 0;
    float keyboadHeightEnd = 0;
    float animationDuration = [[[notif userInfo] objectForKey:UIKeyboardAnimationDurationUserInfoKey] floatValue];
    UIViewAnimationCurve animationCurve = [[[notif userInfo] objectForKey:UIKeyboardAnimationCurveUserInfoKey] unsignedIntegerValue];
#if __IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_3_2
    CGRect keyboardBeginFrame = [[[notif userInfo] objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue];
    CGRect keyboardEndFrame = [[[notif userInfo] objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue];
    keyboadHeightBegin = 480 - keyboardBeginFrame.origin.y;
    keyboadHeightEnd = 480 - keyboardEndFrame.origin.y;
#else
    //these deprecated after iOS 3.2
    CGRect keyboardBounds = [[[notif userInfo] objectForKey:UIKeyboardBoundsUserInfoKey] CGRectValue];
    CGPoint keybordCenterBegin = [[[notif userInfo] objectForKey:UIKeyboardCenterBeginUserInfoKey] CGPointValue];
    CGPoint keybordCenterEnd = [[[notif userInfo] objectForKey:UIKeyboardCenterEndUserInfoKey] CGPointValue];
    keyboadHeightBegin = 480 - (keybordCenterBegin.y - keyboardBounds.size.height / 2);
    keyboadHeightEnd = 480 - (keybordCenterEnd.y - keyboardBounds.size.height / 2);
#endif
    NSLog(@"keyboardHeightChangeFrom:%.2f,To:%.2f",keyboadHeightBegin,keyboadHeightEnd);
    return;
    if (keyboadHeightEnd > 0) {
        //keyboard show or change frame
        [UIView animateWithDuration:animationDuration delay:0 options:animationCurve animations:^{
        } completion:^(BOOL finished) {
        }];
    } else {
        //keyboard hide
    }
}
-(void)keyboardDidChangeFrame:(NSNotification*)notif{
    //info like willChangeFrame
}
-(void)keyboardWillShow:(NSNotification*)notif{
    //keyboard height will be 216, on iOS version older than 5.0
    [UIView animateWithDuration:0.3f animations:^{
        self.contentTableView.height = 480 - 44 - 216;
    }];
}
-(void)keyboardWillHide:(NSNotification*)notif{
    [UIView animateWithDuration:0.3f animations:^{
        self.contentTableView.height = 480 - 44 - 28;
    }];
}
-(void)registerKeyboardEvent{
    float systemVer = [[[UIDevice currentDevice] systemVersion] floatValue];
    if(systemVer >= 5.0) {
        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillChangeFrame:) name:UIKeyboardWillChangeFrameNotification object:nil];
        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardDidChangeFrame:) name:UIKeyboardDidChangeFrameNotification object:nil];
    } else {
        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillShow:) name:UIKeyboardWillShowNotification object:nil];
        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillHide:) name:UIKeyboardWillHideNotification object:nil];
    }
}
-(void)unregisterKeyboardEvent{
    if([[[UIDevice currentDevice] systemVersion] floatValue] > 5.0) {
        [[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillChangeFrameNotification object:nil];
        [[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardDidChangeFrameNotification object:nil];
    } else {
        [[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillShowNotification object:nil];
        [[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillHideNotification object:nil];        
    }
}



下面这个解决方案就只考虑键盘出现和消失的处理

#pragma mark Keyboard
-(void)keyboardWillShow:(NSNotification*)notif{
    //keyboard height will be 216, on iOS version older than 5.0
    CGRect boxFrame = self.loginBoxView.frame;
    boxFrame.origin.y = 50;
    [UIView animateWithDuration:0.3f animations:^{
        self.loginBoxView.frame = boxFrame;
    }];
}
-(void)keyboardWillHide:(NSNotification*)notif{
    CGRect boxFrame = self.loginBoxView.frame;
    boxFrame.origin.y = 216;
    [UIView animateWithDuration:0.3f animations:^{
        self.loginBoxView.frame = boxFrame;
    }];
}
//在viewdidload中调用
-(void)registerKeyboardEvent{
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillShow:) name:UIKeyboardWillShowNotification object:nil];
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillHide:) name:UIKeyboardWillHideNotification object:nil];
}
//在viewdidunload中调用
-(void)unregisterKeyboardEvent{
    [[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillHideNotification object:nil];
    [[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillShowNotification object:nil];
}