<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0">
<channel>
<title>追梦 - WuLeilei's Blog</title>
<link>http://www.wuleilei.com</link>
<description>WuLeilei's Blog</description>
<language>zh-cn</language>
<generator>http://www.wuleilei.com</generator>
<item>
<title>显示 Mac OS X 10.7 Lion 中的用户资源库文件夹</title>
<link>http://www.wuleilei.com/blog/336</link>
<description><![CDATA[
	在 Mac OS X 10.7 Lion 系统中，用户资源库文件夹（Library）被默认隐藏了，可能是由于苹果担心用户不小心误删除用户资源库中的系统必须文件，而故意将这个文件夹隐藏掉了。不过，想让这个文件夹显示出来也非常的简单，直接在终端中执行下面这条命令就可以了：

chflags nohidden ~/Library/

	如果还想让它隐藏的话，执行下面这条命令就可以搞定：

chflags hidden ~/Library]]></description>
<pubDate>Wed, 16 May 2012 05:31:03 +0800</pubDate>
<author>wuleilei</author>
</item>
<item>
<title>iOS开发之int,NSInteger,NSUInteger,NSNumber的使用</title>
<link>http://www.wuleilei.com/blog/335</link>
<description><![CDATA[
	1、当需要使用int类型的变量的时候，可以像写C的程序一样，用int，也可以用NSInteger，但更推荐使用NSInteger，因为这样就不用考虑设备是32位的还是64位的。

	2、NSUInteger是无符号的，即没有负数,NSInteger是有符号的。

	3、有人说既然都有了NSInteger等这些基础类型了为什么还要有NSNumber？它们的功能当然是不同的。

	NSInteger是基础类型，但是NSNumber是一个类。如果想要存储一个数值，直接用NSInteger是不行的，比如在一个Array里面这样用：

NSArray *array= [[NSArray alloc]init];
[array addObject:3];//会编译错误

	这样是会引发编译错误的，因为NSArray里面放的需要是一个类，但&lsquo;3&rsquo;不是。这个时候需要用到NSNumber:

NSArray *array= [[NSArray alloc]init];
[array addObject:[NSNumber numberWithInt:3]];

	Cocoa提供了NSNumber类来包装（即以对象形式实现）基本数据类型。

	例如以下创建方法：

+ (NSNumber*)numberWithChar: (char)value;
+ (NSNumber*)numberWithInt: (int)value;
+ (NSNumber*)numberWithFloat: (float)value;
+ (NSNumber*)numberWithBool: (BOOL) value;

	将基本类型数据封装到NSNumber中后，就可以通过下面的实例方法重新获取它：

- (char)charValue;
- (int)intValue;
- (float)floatValue;
- (BOOL)boolValue;
- (NSString*)stringValue;]]></description>
<pubDate>Tue, 08 May 2012 04:41:17 +0800</pubDate>
<author>wuleilei</author>
</item>
<item>
<title>iOS开发之使用UIGestureRecognizer</title>
<link>http://www.wuleilei.com/blog/334</link>
<description><![CDATA[
	iOS提供了拍击、旋转、滑动、挤捏等丰富的手势，因此对图像的操作就显得非常友好、简单。下面代码展示了使用UIGestureRecognizer对图像进行缩放、移动、旋转操作使用方法。

	在使用代码之前，首先建立一个UIView，并在该视图中增加一个UIImageView视图，用于展示图像。那么该UIView就类似图像画板一样，对图像的操作都基于此视图中进行。

	在视图中创建手势识别器UIGestureRecognizers：

- (void)viewDidLoad {  
    [super viewDidLoad];  
  
    UIPinchGestureRecognizer *pinchRecognizer = [[[UIPinchGestureRecognizer alloc] initWithTarget:self action:@selector(scale:)] autorelease];  
    [pinchRecognizer setDelegate:self];  
    [self.view addGestureRecognizer:pinchRecognizer];  
  
    UIRotationGestureRecognizer *rotationRecognizer = [[[UIRotationGestureRecognizer alloc] initWithTarget:self action:@selector(rotate:)] autorelease];  
    [rotationRecognizer setDelegate:self];  
    [self.view addGestureRecognizer:rotationRecognizer];  
  
    UIPanGestureRecognizer *panRecognizer = [[[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(move:)] autorelease];  
    [panRecognizer setMinimumNumberOfTouches:1];  
    [panRecognizer setMaximumNumberOfTouches:1];  
    [panRecognizer setDelegate:self];  
    [canvas addGestureRecognizer:panRecognizer];  
  
    UITapGestureRecognizer *tapProfileImageRecognizer = [[[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tapped:)] autorelease];  
    [tapProfileImageRecognizer setNumberOfTapsRequired:1];  
    [tapProfileImageRecognizer setDelegate:self];  
    [canvas addGestureRecognizer:tapProfileImageRecognizer];  
}

	下面是响应各手势消息的方法：

// 缩放  
-(void)scale:(id)sender {  
  
    if([(UIPinchGestureRecognizer*)sender state] == UIGestureRecognizerStateBegan) {  
      _lastScale = 1.0;  
    }  
  
    CGFloat scale = 1.0 - (_lastScale - [(UIPinchGestureRecognizer*)sender scale]);  
  
    CGAffineTransform currentTransform = photoImage.transform;  
    CGAffineTransform newTransform = CGAffineTransformScale(currentTransform, scale, scale);  
  
    [photoImage setTransform:newTransform];  
  
    _lastScale = [(UIPinchGestureRecognizer*)sender scale];  
    [self showOverlayWithFrame:photoImage.frame];  
}  
  
// 旋转  
-(void)rotate:(id)sender {  
  
    if([(UIRotationGestureRecognizer*)sender state] == UIGestureRecognizerStateEnded) {  
  
      _lastRotation = 0.0;  
      return;  
    }  
  
    CGFloat rotation = 0.0 - (_lastRotation - [(UIRotationGestureRecognizer*)sender rotation]);  
  
    CGAffineTransform currentTransform = photoImage.transform;  
    CGAffineTransform newTransform = CGAffineTransformRotate(currentTransform,rotation);  
  
    [photoImage setTransform:newTransform];  
  
    _lastRotation = [(UIRotationGestureRecognizer*)sender rotation];  
    [self showOverlayWithFrame:photoImage.frame];  
}  
  
// 移动  
-(void)move:(id)sender {  
  
  CGPoint translatedPoint = [(UIPanGestureRecognizer*)sender translationInView:canvas];  
  
  if([(UIPanGestureRecognizer*)sender state] == UIGestureRecognizerStateBegan) {  
    _firstX = [photoImage center].x;  
    _firstY = [photoImage center].y;  
  }  
  
  translatedPoint = CGPointMake(_firstX+translatedPoint.x, _firstY+translatedPoint.y);  
  
  [photoImage setCenter:translatedPoint];  
  [self showOverlayWithFrame:photoImage.frame];  
}

	自定义手势：http://blog.csdn.net/dongge_111/article/details/7364313]]></description>
<pubDate>Thu, 03 May 2012 02:58:38 +0800</pubDate>
<author>wuleilei</author>
</item>
<item>
<title>iOS开发之使用lipo命令制作模拟器与真机通用静态库</title>
<link>http://www.wuleilei.com/blog/333</link>
<description><![CDATA[
	通常在项目中使用静态库的时候都会有两个版本，一个用于模拟器，一个用于真机，因为Mac和iPhone的CPU不同，才造成了这种情况。

	为了模拟器与真机之间切换调试的方便，制作通用版本非常有必要。

	现在有两个版本的静态库libSQLite_i386.a（模拟器）与libSQLite_arm.a（真机）。

	1、打开终端，进入到这两个文件所在的目录；

	2、执行：lipo -create libSQLite_i386.a libSQLite_arm.a -output libSQLite.a，这时文件就会多出libSQLite.a，这个文件即为通用静态库。

	我们可以lipo -info libSQLite.a命令，查看是否是通用的。

	可以发现libSQLite.a的大小为libSQLite_i386.a与libSQLite_arm.a之和，建议发布的时候将静态库替换成真机版。]]></description>
<pubDate>Sat, 28 Apr 2012 06:12:42 +0800</pubDate>
<author>wuleilei</author>
</item>
<item>
<title>iOS开发之KVO的使用</title>
<link>http://www.wuleilei.com/blog/332</link>
<description><![CDATA[
	一、概述

	KVO，即：Key Value Observing，直译为：基于键值的观察者。

	它提供一种机制，当指定的对象的属性被修改后，对象就会接受到通知。简单的说就是每次指定的被观察的对象的属性被修改后，KVO就会自动通知相应的观察者。

	在下文的示例中。图书（Book类），就是个实体。它的属性有书名（name）和价格（price）。那么，在界面开发中，可能有多个视图和这个实体有关联。如果实体（Book）的价格（price）发生了变化，这些关联的界面都要被修改。

	二、使用方法

	系统框架已经支持KVO，所以程序员在使用的时候非常简单。

	1. 注册，指定被观察者的属性；

	2. 实现回调方法；

	3. 移除观察。

	三、实例

	假设有一个Book类，此类有name和price属性，当price发生变化时，界面上的价格立刻显示为最新的价格。

	1. Book类，头文件：

#import &lt;Foundation/Foundation.h&gt;

@interface Book : NSObject {
    NSString *name;
    float price;
}

@end

	Book类的实现文件，没做任何事情，不贴了。

	2. 在viewController里面实例化它，监听它的属性，并在label中显示它的属性。

_book = [[Book alloc] init];
[_book setValue:@&quot;C语言&quot; forKey:@&quot;name&quot;];
[_book setValue:@&quot;10.0&quot; forKey:@&quot;price&quot;];
[_book addObserver:self forKeyPath:@&quot;price&quot; options:NSKeyValueObservingOptionNew|NSKeyValueObservingOptionOld context:nil];

	3. 点击button的时候，更改book的price属性。

- (IBAction)changePrice:(id)sender
{
    [_book setValue:@&quot;12.1&quot; forKey:@&quot;price&quot;];
}

	4. 实现回调方法。

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
    if ([keyPath isEqualToString:@&quot;price&quot;]) {
        NSLog(@&quot;%@&quot;, change);
    }
}

	5. 增加观察与取消观察是成对出现的，所以在book释放前，要删除观察者。

- (void)dealloc
{
    [_book removeObserver:self forKeyPath:@&quot;price&quot;];
    [_book release];
    [super dealloc];
}

	点击此处下载示例。]]></description>
<pubDate>Wed, 11 Apr 2012 04:59:06 +0800</pubDate>
<author>wuleilei</author>
</item>
<item>
<title>iOS中后台运行</title>
<link>http://www.wuleilei.com/blog/331</link>
<description><![CDATA[
	iOS在升级到4.0以后就支持了多任务了。下文将详细介绍一下这个特性。

	1、检查设备是否支持多任务

	Apple出于性能的考虑，并不是所有的iOS设备升级到iOS4以后都支持多任务，比如iPhone 3G。如果你的应用在没有多任务特性时会出问题，为了保持应用的健壮性，你应该对此进行判断并处理。你可以通过调用UIDevice对象的multitaskingSupported属性来获取当前设备是否支持多任务。

if(![UIDevice currentDevice].multitaskingSupported){
    //不支持多任务时应做的处理
}

	2、基本多任务特性

	通常，当用户按一下Home键，当前应用就会被进入后台，应用处在后台运行状态一小段时间后，就会进入挂起（suspend）状态，此时应用不会再执行任何代码。如果系统在运行其他应用时内存资源不足，这个挂起的应用甚至有可能被系统退出，释放内存以供活动的应用使用。只有当用户再次运行此应用，应用才会从挂起状态唤醒，代码得以继续执行。这就是iOS4带来的基本的多任务特性，这个特性是一般应用默认支持的，就是说你的应用不需要任何修改就能支持基本多任务特性。

	既然是多任务你应该会在应用进入后台时做一些处理，比如暂停一些界面的定时刷新或网络请求。同时，或者你会在程序进入前台时执行一些恢复操作。在你的应用的application delegate里有2个消息用于处理这些消息：

- (void)applicationDidEnterBackground:(UIApplication *)application {
     //进入后台时要进行的处理
}
- (void)applicationWillEnterForeground:(UIApplication *)application {
     //进入前台时要进行的处理
}

	当然你也许不会都在application delegate处理所有的事情。如果你要在其他对象中处理，那么你就需要注册系统通知了，这两个通知分别是UIApplicationDidEnterBackgroundNotification和UIApplicationWillEnterForegroundNotification。

	也许你需要更多的多任务特性，比如后台播放音乐或者是后台进行GPS跟踪。这会是下面介绍的内容。

	3、后台播放音

	通常，一般应用在进入后台时，任何声音就将会停止。这也许不是我们所想要的。要想让自己的应用支持后台播放，首先要修改应用的Info.plist 文件，你需要在Info.plist文件中添加UIBackgroundModes字段，该字段的值是应用支持的所有后台模式，是一个数值类型。目前此数 组可以包含&ldquo;audio&rdquo;、&ldquo;location&rdquo;和&ldquo;voip&rdquo;这三个字符串常量，如果要支持后台音乐播放，你就需要包含&ldquo;audio&rdquo;，其余两个会将在 后面讲到。

	同时，你也应该设置一下应用程序的Audio Sesstion。这个是必需的，如果不设置Audio Sesstion，应用就可能进入后台时Audio Sesstion失活而停止播放。一般需要这么设置就可以了：

[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback error:nil];

	4、后台GPS跟踪

	和后台播放音乐类似，若要支持后台GPS跟踪，你就需要在Info.plist文件中UIBackgroundModes字段对应的数组中增加&ldquo;location&rdquo;字符串。

	5、后台voip支持

	由于voip应用需要一个长连接到服务器，为了让这类应用能正常工作，iOS中加入后台voip支持特性。为支持这一特性，需要在Info.plist文件中UIBackgroundModes字段对应的数组中增加&ldquo;voip&rdquo;字符串。

	此外你仍然需要配置一下你的网络连接，以便支持后台连接。iOS提供的网络连接库有几种，下面一一说明：

	如果你使用的是NSStream，如NSInputStream或NSOutputStream，需要调用setProperty:forKey:将Key为NSStreamNetworkServiceType的value设置为NSStreamNetworkServiceTypeVoIP。

	如果你使用NSURLRequest，需要调用setNetworkServiceType:将网络类型设置为NSURLNetworkServiceTypeVoIP。

	如果你使用CFStream，如CFReadStreamRef或CFWriteStreamRef，需要调用 CFReadStreamSetProperty或CFWriteStreamSetProperty将 kCFStreamNetworkServiceType属性设置为kCFStreamNetworkServiceTypeVoIP。]]></description>
<pubDate>Mon, 02 Apr 2012 04:10:22 +0800</pubDate>
<author>wuleilei</author>
</item>
<item>
<title>Mac OS X中使用AppCleaner干净的卸载应用程序</title>
<link>http://www.wuleilei.com/blog/330</link>
<description><![CDATA[
	在Mac OS X上删除应用程序是一件很简单的事情，只要将应用程序直接删除就可以了。这种删除方式对于大多数的应用来说都是适用的，但是这种删除其实并没有将这个程序相关联的所有文件全部删除掉，有一些配置文件还会遗留在系统中。介绍这款小软件AppCleaner，可以帮助你更加干净的删除应用程序。

	下载AppCleaner，然后运行。我们可以看到AppCleaner的界面非常简洁。

	

	AppCleaner的操作也非常简单，只要把你想要删除的应用程序拖拽到AppCleaner就可以了。拖拽进去后，AppCleaner就会显示将要删除的文件。这时你会看到，一些相关的配置文件都会同时删除。点击&ldquo;Delete&rdquo;按钮，就完成删除了。简单吧:-)

	

	除此之外，当我们点击Applications按钮后，AppCleaner会列出系统中所有的应用。这时，你可以选中多个应用，同时进行删除。

	

	除了删除应用程序外，AppCleaner还可以帮助你删除Widget和一些Plugin。只要点击工具栏上的&rdquo;Widgets&rdquo;和&rdquo;Others&rdquo;按钮就可以看到了。

	这里有一点要注意的就是，AppCleaner并不能应用于所有应用程序的删除。有些应用比较复杂，关联的文件很多，像Adobe的应用，以及Parallels。一般情况下，这些应用会提供自己的Uninstall文件。所以当我们删除一个应用的时候，应该先看一下这个应用是否有对应的反安装文件，然后再选择合适的删除方式。]]></description>
<pubDate>Tue, 27 Mar 2012 04:48:28 +0800</pubDate>
<author>wuleilei</author>
</item>
<item>
<title>iOS开发之对象序列化和反序列化</title>
<link>http://www.wuleilei.com/blog/329</link>
<description><![CDATA[
	Objective-C可以将程序用到的各种对象序列化到文件，在任何需要的情况下，从文件中重新读取数据重新构造对象，下面说一下对象的序列化和反序列化。

	使用NSKeyedArchiver把对象序列化到文件中：

// 数组对象
NSString *saveStr1 = @&quot;NSKeyedArchiver1&quot;;
NSString *saveStr2 = @&quot;NSKeyedArchiver2&quot;;
NSArray *array = [NSArray arrayWithObjects:saveStr1, saveStr2, nil];
// 将路径和文件名合成文件完整路径 
NSString *Path = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)objectAtIndex:0];
NSString *filename = [Path stringByAppendingPathComponent:@&quot;saveDatatest&quot;];
// 将数组对象序列化到文件
[NSKeyedArchiver archiveRootObject:array toFile:filename];

	使用NSKeyedUnarchiver从文件中反序列化成对象：

array = [NSKeyedUnarchiver unarchiveObjectWithFile: filename];
NSLog(@&quot;%@&quot;,array);]]></description>
<pubDate>Thu, 22 Mar 2012 08:11:04 +0800</pubDate>
<author>wuleilei</author>
</item>
</channel>
</rss>
