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.htmlX124X
另外一个来自百度百科的条目,其中有正则表达式各个字符的含义
正则表达式字符含义在此

在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];
}

linux/mac下的自定义命令alias,并保存别名使其永久生效(重启不会失效)

现在做开发每次提交代码的命令都是一长串参数,不想去记,于是可以使用alias命令来解决这个问题:
alias aCommandAlias='aCommand 一堆参数什么的'
比如
alias gpush='git push origin HEAD:refs/for/master'

这样在终端中,只需要输入gpush就ok了。

但是只是这样的话,会在重启之后失效,解决办法是编辑~/.bashrc文件,每行加入一个alias命令。比如:
alias cdhome='cd ~'
alias cdroot='cd /'
alias gpull='git pull'
alias gci='git commit -a'
alias gpush='git push origin HEAD:refs/for/master'
alias gst='git status'

保存文件后,运行:
source ~/.bashrc(不然不生效)
就可以了。
如果还不行的话,说明没有~/.bash_profile文件,或者文件中没有执行.bashrc文件。
(.bash_profile文件是用户登陆终端的时候会自动执行的文件,一般此文件中会调用.bashrc)
如果是这样,需要打开(如果没有的话先创建)文件:
~/.bash_profile
在里面加入一行:
source ~/.bashrc
就ok了。
我在mac系统下测试ok的。

【转】ubuntu安装pptpd来架设VPN服务器

转自:http://www.cnblogs.com/youlechang123/archive/2011/09/29/2195013.html
今天用此法尝试了一下,很顺利就ok了

—————–一下是原文——————–
这篇文章是以前写的了,不过那个网址好像由于fan墙两个字被拦截屏蔽了,一打开就整个域名被屏蔽几十秒,把敏感字做了处理好像还不行,重新发一次,NND,有兴趣打开试下看看:ubuntu架设VPN服务器

Linux下的VPN服务器软件主要是pptpd和openvpn,pptpd架设好后在windows下建个VPN连接就可以fan墙了,比较简单,这里说下ubuntu下安装配置pptpd。首先安装pptpd这个VPN服务器软件,ssh连接登录后用下面这个命令:

sudo apt-get install pptpd

安装好了在webmin的网络这一栏里就可以看到pptp vpn server这项了。

安装完了需要对相关文件进行配置修改,用webmin上的文件管理或ssh端用vi命令修改都行。

第一步:

方法一:ssh连接修改/etc/pptpd.conf这个文件

vi /etc/pptpd.conf

找到#localip 192.168.0.1和#remoteip 192.168.0.234-238,192.168.0.245这两行,把前面的#号去掉,然后保存就行了。

这里,localip 是 VPN 链接成功后服务器的 ip 地址, remoteip 则客户端的可分配 ip 地址范围。下面是我的配置:

(Recommended)

localip 192.168.0.1

remoteip 192.168.0.234-238,192.168.0.245

or

localip 192.168.0.234-238,192.168.0.245

localip 192.168.0.234-238,192.168.0.245

remoteip 192.168.1.234-238,192.168.1.245

方法二:用webmin的pptpd服务器项修改,点击webmin网络>PPTP VPN Server>PPTP Server Options,加上localip和romoteip就行了,如下图

第二步:

然后再要编辑/etc/ppp/pptpd-options这个文件,为vpn指定DNS服务器, 你可以找到你服务器用的DNS服务器地址,或者直接使用Google Public DNS:

vi /etc/ppp/pptpd-options

找到ms-dns这项,去掉前面的#号,修改成google提供的DNS,很好记哈

ms-dns 8.8.8.8

ms-dns 8.8.4.4

修改好后保存。

第三步:

接下来建立vpn账号和密码了,可以直接在webmin的pptp vpn server选项里修改,修改文件也行。

方法一:点击webmin里的网络>PPTP VPN Server>PPP Accounts>Create new PPP account,就可以创建新的账号和密码了。

webmin创建VPN账号

方法二:修改/etc/ppp/chap-secrets文件,按一行四列添加账号、服务器名、密码和IP限制。即第一列是用户名,第二列是服务器名(默认写pptpd 即可,注意与 pptpd-options 文件保持一致),第三列是密码,第四列是 IP 限制(不做限制用 * )。如创建一个名为test,密码为123,不限制登录IP的VPN账号:

test pptpd 123 *

修改好后保存行了。

最后重启pptpd服务,就可以生效了。

到了这一步,正常的话在XP里建立个VPN连接应该可以连接上了,但还不能访问外网,还需要另外的配置。但是如果连接不上VPN服务器的话,那就是碰上传说中的人品问题了,我就碰到过,明明所有步骤都做了,但是就是不能连接上,然后就胡乱折腾,看运气什么时候能折腾好了。

继续下一步,第四步:

修改/etc/sysctl.conf 这个文件,把ipv4 forward开启,方法是找到/etc/sysctl.conf这个文件里的这一行#net.ipv4.ip_forward=1后,去掉net.ipv4.ip_forward=1前面的#号,使他生效,然后保存,运行命令sysctl –p.

root@s:~# sysctl -p

运行命令后会显示这样的一行,那就表示修改生效了。

net.ipv4.ip_forward = 1

这样,vpn 服务器就算是搭建成功了。

重启pptpd后如果还不能访问外网,那么就要再来一步。

第五步:

使用iptables建立一个NAT, 用下面的命令:

apt-get install iptables (如果已经安装iptables,这一步就不用了)

iptables -t nat -A POSTROUTING -s 192.168.0.0/24 -o eth0 -j MASQUERADE

上面的24表示子网掩码,代表24个1.

OK,到了这一步就应该可以用VPN了哈。如果不能,我也不知是哪里出问题了。

如果要防止重启服务器后iptables丢失,先运行

iptables-save > /etc/iptables-rules

然后修改/etc/network/interfaces 文件,在eth0 下面加入

pre-up iptables-restore < /etc/iptables-rules

这样,服务器重启后,就能自动挂载规则了。

好了,有了VPN,墙再高也不怕了哈。

利用JavaScript从UIWebView获取、修改、提交网页内数据的方法

在UIWebView的内容加载完之后,可以利用javascript获取其页面内的数据,核心就是通过UIWebView的方法:

NSString *string = [awebView stringByEvaluatingJavaScriptFromString:@"document.getElementById('field_2').value;" ];

以下是一些常用的js脚本:

thisURL = document.URL;
thisHREF = document.location.href;
thisSLoc = self.location.href;
thisDLoc = document.location;
thisTLoc = top.location.href;
thisPLoc = parent.document.location;
thisTHost = top.location.hostname;
thisHost = location.hostname;
thisTitle = document.title;
thisProtocol = document.location.protocol;
thisPort = document.location.port;
thisHash = document.location.hash;
thisSearch = document.location.search;
thisPathname = document.location.pathname;
thisHtml = document.documentElement.innerHTML;
thisBodyText = document.documentElement.innerText;//获取网页内容文字
thisBodyText = document.body.innerText;//获取网页内容文字

也可以通过同样的方法去设置页面内容(比如帮用户输入表单数据)
比如:
NSString *string = [awebView stringByEvaluatingJavaScriptFromString:@"document.getElementById('field_2').value='a value';" ];
就可以修改field_2的值了

同样也可以去模拟页面内按钮的点击,提交页面,比如:
document.getElementById('aButtonName').click();
或者,假设知道按钮是第几个input标签(假设为第一个)
document.getElementsByTagName('input').item(0).click();
也可以设置checkBox的状态:
document.getElementById('aCheckBoxId').checked=true;

参考:
http://hi.baidu.com/zfpp25/blog/item/0bc5e3565a7e632e0cf3e3d7.html
http://www.cnblogs.com/del/archive/2009/01/07/1370907.html
http://blog.csdn.net/studyrecord/article/details/6213843

使用sina开放平台的ios sdk做微博转发,调用repost接口返回auth faild错误

今天遇到一个问题,在调用statuses/repost.json接口的时候,总是返回auth faild错误。
但是发布微博是可以的,而且api文档中repost接口和upload接口是一个等级的,应该不是权限问题,于是各种茫然。
在尝试各种方法,搜索无果后,只能去sina api论坛提问(帖子传送门,问题已解决)
然后不幸的是,发现评论一条微博的接口@”comments/create.json”也存在同样问题。
在等待论坛回应的过程中,无意中发现一句代码:

postDataType:kWBRequestPostDataTypeMultipart

然后跟踪到正常工作的发布微博接口中去看看,发现微博发布接口中,有图片的时候,是用multipart,但是在只有text的时候,用的是:

postDataType:kWBRequestPostDataTypeNormal

于是把转发和评论都改成normal之后,正常了。。

———– 后话 ————-
其实一开始我尝试过一共三种postdatatype,都不正常,包括normal。。因为在当时还存在另一个bug,就是微博的id,返回类型是int64的,我一直当做string在用。所以在我设置成normal的时候,报错参数传递缺少(id)字段。。后来我把id打印出来,直接硬编码在代码中,终于转发成功了一次,这样才解决了auth faild的问题以及发现这个bug。。。

多个bug一起出现,更据迷惑性啊··

再后来,发现很多调用出现auth faild的错误原因都在于postDataType:kWBRequestPostDataTypeNormal没有设置正确。

iOS开发中创建和使用静态链接库(.a)

创建静态库项目之后,Build,然后就能看到Product中的.a文件亮了,然后能把它拷出来加到别的项目中去使用,但是貌似.h文件没有在这个地方出现,还是得手动去找?
反正我是直接在目录下搜.h文件,全部拷贝和.a文件一起加入目标项目来使用是可以的。

另外貌似要区分iphone-simulator和iphone两个不同scheme生成的.a文件,不能混用。
今天(5月18)验证了一下,确实是这样的,需要区别对待,可以在target是iphone下编译一个.a,再在simulator下编译一个.a。两个.a同时拷贝到目标项目才行。不然的话,链接阶段会报错,这个挺烦人。。应该有解决办法,目前没时间找。
合并模拟器和设备的静态库实际很简单,如果一个是somelib.sim.a,一个是somelib.device.a,只需要在命令行运行:
lipo -create somelib.sim.a somelib.device.a -output somelib.a
就可以了

参考:
http://xys289187120.blog.51cto.com/3361352/786930
http://blog.csdn.net/flyhawk007j2me/article/details/6762798

iOS开发中对NSArray或者NSMutableArray中的内容排序

在iOS开发中,排序是很简单的事情:


NSMutableArray *feedsBuffer;
//初始化buffer以及填充数据
//.......
//排序只需要两句话:已针对数组内对象的publishTime属性(NSDate)排序为例:
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"publishTime" ascending:NO];
[feedsBuffer sortUsingDescriptors:[NSArray arrayWithObject:sortDescriptor]];

假如feedsBuffer是NSArray,那么有一个方法是

NSArray *sortedArray = [feedsBuffer sortedArrayUsingDescriptors:[NSArray arrayWithObject:sortDescriptor]];

如果排序的依据比较复杂,那么可以使用Block进行大小判断自定义:

[feedsBuffer sortUsingComparator:^NSComparisonResult(id obj1, id obj2) {
//返回三者其一:NSOrderedAscending, NSOrderedSame, NSOrderedDescending
return NSOrderedSame;
}];

wordpress开启多站点支持

wordpress 3.0 开始就支持多站点了,不过默认是关闭的。
开启的方式也很简单,那就是在 wp-config.php文件最后添加一句

define('WP_ALLOW_MULTISITE', true);

之后就能在”工具(tools)”里面多出来一项”设置网络(networks)”,照着一步一步做就ok了。

如果采用子域名的方式,需要开启apache的rewrite。

对于apache1,开启方式是反注释掉httpd.conf中对应的语句。有一句
#Load什么什么rewrite什么的
去掉前面的#就可以了

对于apache2,执行
sudo a2enmod rewrite
就可以了

iOS内存Bug

一个bug找了我好长时间····

UIView *view = array.lastObject;
if (view) {
[[view retain] autorelease];
[array removeLastObject];
}
return view;
[[view retain] autorelease];

这一句话不加害死人啊··

在iOS中利用CLMapKit进行地理位置反向编码(ReverseGeoCoding)

在iOS开发中,可以很方便地通过CLMapKit进行反向解码,即从一个坐标(经度xxx,维度yyy)得到其相对来说更有意义的地名,如(北京市海淀区颐和园路北京大学)
代码很简单如下:

-(void)reversGeoCoding{
    if (!self.geoCoder) {
        self.geoCoder = [[CLGeocoder alloc] init];
    }
    CLLocation *location = [[CLLocation alloc] initWithLatitude:latitude longitude:longitude];
    [self.geoCoder reverseGeocodeLocation:location completionHandler:^(NSArray *placemarks, NSError *error) {
        NSLog(@"geoCode completed");
        CLPlacemark *placemark = [placemarks lastObject];
        if (placemark) {
            NSLog(@"%d placemark found:%@",placemarks.count,placemark);
            NSString *str = placemark.name;
            if (str && str.length > 0) {
                self.subtitle = str;
            }
        }
    }];
}

iOS CAPropertyAnimation 动画(transform部分)

在iOS开发中,经常会涉及到动画的制作。简单的动画通过UIView的Animation就可以实现了,但是对于稍微复杂的动画,还是得借助于CoreAnimation来实现。
CoreAnimation可以针对CALayer的属性设置动画(CAPropertyAnimation和CAKeyFrameAnimation),设置动画的keyPath就可以了。
keyPath是一个NSString类型的成员,其可用范围有哪些呢?
可以是CALayer.h中列出来的属性(h文件中针对可以动画的都写有:”Animatable”),除此之外还有更多的设置选项。
本文先讨论transform部分。
transform可以是一个CATransform3D,借助于这个4*4矩阵,可以进行3D动画的模拟,想象一下Mac的Finder中的动画效果吧。

如果只是在keyPath设置transform矩阵是比较复杂的。好在其提供了更多的keyPath可供选择来简化动画设置:

Table 4 CATransform3D key paths
Field Key Path Description
rotation.x The rotation, in radians, in the x axis.
rotation.y The rotation, in radians, in the y axis.
rotation.z The rotation, in radians, in the z axis.
rotation The rotation, in radians, in the z axis. This is identical to setting the rotation.z field.
scale.x Scale factor for the x axis.
scale.y Scale factor for the y axis.
scale.z Scale factor for the z axis.
scale Average of all three scale factors.
translation.x Translate in the x axis.
translation.y Translate in the y axis.
translation.z Translate in the z axis.
translation Translate in the x and y axis. Value is an NSSize or CGSize.

比如想实现针对x轴的旋转动画,只需要按如下代码:

// test animation on transform3D
CALayer *layer = testView.layer;
CATransform3D trans = CATransform3DIdentity;
trans.m34 = 0.002;
layer.transform = trans;
CAKeyframeAnimation *ani = [[CAKeyframeAnimation alloc] init];
ani.keyPath = @"transform.rotation.x";
ani.values = [NSArray arrayWithObjects:[NSNumber numberWithFloat:0],[NSNumber numberWithFloat:M_PI], nil];
ani.repeatCount = INFINITY;
// ani.repeatDuration = 300;//总时间,相当于duration * repeatCount
ani.duration = 3;//每一个循环的时间
[testView.layer addAnimation:ani forKey:@"testAni"];

另外,其实UIView.center属性,UIView.layer.transform属性,都可以用UIView的Animation来实现简单的动画。

夜的钢琴曲5

Music一枚 夜的钢琴曲5

好安静的感觉

Audio MP3

小小-容祖儿

一首好听的歌,小小 容祖儿

Audio MP3

WordPress更新插件需要FTP权限的问题

WordPress在发现其所在目录的所有者和进程所有者不一致时会跳转到一个页面让填写ftp信息。解决办法如下:

运行
ps -aux
查看httpd进程或者apache2进程的用户名,比如我看见是www-data

切换到Wordpress的安装路径,比如wordpress安装在位置/www/wordpress ,就切换到/www目录,执行:
chown -R www-data:www-data wordpress

然后就OK了。

vim 命令

vim命令整理备忘

先整理常用命令

切换状态:

i   进入插入模式
ESC   退出插入模式

常用:

h,j,k,l    移动光标
:w   保存
:q  退出
:wq和:x 保存修改并退出
:q!  强退
x 删除当前字符
dd 删除当前行
p 粘贴到当前行下面
yy 复制当前行,可以在前面加数字表示复制多少行

/patten 查找字符串patten
n 继续向下查找
N 反向查找