来源:http://stackoverflow.com/questions/2506647/iphone-flip-animation-when-controller-pushed 

总所周知,在 CoCoa Touch 中通过设置 modalTransitionStyle 属性可以很方便地在切换 ViewController 的时候实现各种动画效果,但如果使用 pushViewController 则不会出现如何效果,如果在 pushViewController 中实现 Flip 的翻页的效果呢? 废话不多说,上代码:

[UIView beginAnimations:@"animation" context:nil];
[self.navigationController pushViewController:myController animated:NO];
[UIView setAnimationTransition:UIViewAnimationTransitionFlipFromLeft forView:self.navigationController.view cache:NO]; 
[UIView setAnimationDuration:0.7];
[UIView commitAnimations];
VN:F [1.9.22_1171]
Rating: 8.5/10 (2 votes cast)
VN:F [1.9.22_1171]
Rating: +1 (from 1 vote)

Xcode

众所周知,在Xcode中的IDE环境中编译和调试程序十分方便,我们在某行代码中设置好断点,当程序执行到该处时,只需要将鼠标放到代码段中的字符串等变量名上面,Xcode就能显示出变量的内容。但如果是一些稍微复杂的变量类型,诸如NSDictionary,还是无法看到字典里的全部字段的内容。如果用NSLog去自己写代码输出的话,又嫌有些麻烦。Google了一下,在伟大的StackOverFlow网站找到一个好方法。

这个时候,我们可以开启Debuger,来追踪到具体的内容。在代码的断点处使用快捷键command+shift+Y,调出Debuger窗口,在左侧选择你的代码文件,右侧会列出该代码段的变量列表,选择你所需要追踪的数据,这里我找到了要查看的变量parameters,这是一个NSDictionary类型。点击右键,选择Print Description to Console。如下图所示:

xCode-Debuger
找到需要查看的变量名

然后打开Xcode的控制台(command+shift+R),就能看到详细的信息了。很简单吧,高手可以无视了,对于我这个Xcode菜鸟来说,真的很方便了。

NewImage
数据显示在控制台了

VN:F [1.9.22_1171]
Rating: 8.4/10 (7 votes cast)
VN:F [1.9.22_1171]
Rating: 0 (from 2 votes)

 在Xcode中从网络中调用多图片并显示在UITableView中的时候,如果只用主线程调用函数的方法,在载入图片的时候,整个界面会凝固掉,只有在图片读取完毕后,界面才会恢复。这个时候就需要考虑开另一个读取图片的线程,等该线程读取完毕数据后,再刷新整个界面。但传统的线程方式问题很多,经常要考虑之间的数据保护和死锁等问题。在Cocoa中,Apple提供了 NSOperation这个类,提供了一个优秀的多线程编程方法,让我们不用关注太多的其它问题。话不多说,上代码:

- (void) loadCacheImages{
	/* 建立线程操作队列 */
    NSOperationQueue *queue = [NSOperationQueue new];
	
    /* 创建一个NSInvocationOperation对象来在线程中执行loadImagesWithThread操作 */
    NSInvocationOperation *operation = [[NSInvocationOperation alloc] initWithTarget:self
        selector:@selector(loadImagesWithThread) 
        object:nil];
	
    /* 将operation添加到线程队列 */
    [queue addOperation:operation];
    [operation release];
	
}

- (void) loadImagesWithThread{
	//线程从这里执行,可以向普通操作一样读取图片、完成后刷新界面等
}
	
}

对于UITableview来说,可以将图片保存到一个字典中,用url作为key, UIImage对象作为内容。然后在其代理方法cellForRowAtIndexPath中处理这些图片数据(cell.image)即可。

VN:F [1.9.22_1171]
Rating: 10.0/10 (1 vote cast)
VN:F [1.9.22_1171]
Rating: +1 (from 1 vote)

CoCoa中可以很方便地使用RGB三个值来初始化一个UIColor对象,今天碰到一个需求,已经知道一个UIColor的情况下,如何分离出它的RGB值呢?

其实很简单,Google了一下,找到一个方法,记录备忘。

CGFloat R, G, B;
	
UIColor *uiColor = [lblDate textColor];
CGColorRef color = [uiColor CGColor];
int numComponents = CGColorGetNumberOfComponents(color);

if (numComponents == 4)
{
	const CGFloat *components = CGColorGetComponents(color);
	 R = components[0];
	 G = components[1];
	 B = components[2];
}
VN:F [1.9.22_1171]
Rating: 8.3/10 (4 votes cast)
VN:F [1.9.22_1171]
Rating: +1 (from 1 vote)

xcode.jpg

这么多年来断断续续用了各种各样的编程语言,说到最方便,还是喜欢PHP。初次使用的时候就被其数组的强大功能所吸引,各种各样杂七杂八无穷无尽千奇百怪的函数,PHP里面都有。常常在写PHP代码的时候,会想要个功能,就会直接按照自己的想法打个函数名上去,结果PHP还真有这个函数,再查查手册,八九不离十,牛X…有时候想临时写个小程序,如图片处理、文件整理、数据分析,用PHP来整,还真是方便。

回到正题,最近学习Objective-C,有一个需求,就是计算两个日期之间的间隔。普通的方法是两个日期做个减法,根据间隔算时间。这个做法符合数学逻辑,但不符合生活逻辑。比如昨天晚上11点和今天凌晨1点,虽然之间隔两个小时,但按照生活逻辑来说,应该算是一天。所以,应该取两个日期的午夜零点的时间来进行计算。当然Objective-C没有这样的生活逻辑函数库,只有自己动手丰衣足食了。

本来想自己整代码的,Google的时候发现了一个开源的Objective-C的库,网友做的简单的NSDate类的一些扩展NSDate-Helper,实现了上述的生活逻辑算法和其它的一些库,挺好用的,拿来主义之。

NSDate-Helper开源库地址:http://github.com/billymeltdown/nsdate-helper

扩展的内容:

- (NSUInteger)daysAgo;
- (NSUInteger)daysAgoAgainstMidnight;
- (NSString *)stringDaysAgo;
- (NSString *)stringDaysAgoAgainstMidnight:(BOOL)flag;
- (NSUInteger)weekday;

+ (NSDate *)dateFromString:(NSString *)string;
+ (NSDate *)dateFromString:(NSString *)string withFormat:(NSString *)format;
+ (NSString *)stringFromDate:(NSDate *)date withFormat:(NSString *)string;
+ (NSString *)stringFromDate:(NSDate *)date;
+ (NSString *)stringForDisplayFromDate:(NSDate *)date;
+ (NSString *)stringForDisplayFromDate:(NSDate *)date prefixed:(BOOL)prefixed;

- (NSString *)string;
- (NSString *)stringWithFormat:(NSString *)format;
- (NSString *)stringWithDateStyle:(NSDateFormatterStyle)dateStyle timeStyle:(NSDateFormatterStyle)timeStyle;

- (NSDate *)beginningOfWeek;
- (NSDate *)beginningOfDay;
- (NSDate *)endOfWeek;

+ (NSString *)dateFormatString;
+ (NSString *)timeFormatString;
+ (NSString *)timestampFormatString;
+ (NSString *)dbFormatString;

不知道有没有更好的扩展库,目前就用这个了,记在自己的日志中,备忘存档。

VN:F [1.9.22_1171]
Rating: 10.0/10 (2 votes cast)
VN:F [1.9.22_1171]
Rating: +1 (from 1 vote)

内存泄露是个大问题,但总小心翼翼管理内存,经常也会出现释放错误。最近学习objective-c,不是忘记释放内存导致内存泄露,就是提早释放导致内容非法访问。唉,至少找点教程来研究研究,这篇不错,放在博客上备忘。

版权声明:此文版权归作者Vince Yuan (vince.yuan#gmail.com)所有。欢迎非营利性转载,转载时必须包含原始链接http://vinceyuan.cnblogs.com/,且必须包含此版权声明的完整内容。

版本 1.1  发表于2010-03-08

前言

初学objectice-C的朋友都有一个困惑,总觉得对objective-C的内存管理机制琢磨不透,程序经常内存泄漏或莫名其妙的崩溃。我在这里总结了自己对objective-C内存管理机制的研究成果和经验,写了这么一个由浅入深的教程。希望对大家有所帮助,也欢迎大家一起探讨。

此文涉及的内存管理是针对于继承于NSObject的Class。

一 基本原理

Objective-C的内存管理机制与.Net/Java那种全自动的垃圾回收机制是不同的,它本质上还是C语言中的手动管理方式,只不过稍微加了一些自动方法。

1. Objective-C的对象生成于堆之上,生成之后,需要一个指针来指向它。

ClassA *obj1 = [[ClassA alloc] init]; 

2. Objective-C的对象在使用完成之后不会自动销毁,需要执行dealloc来释放空间(销毁),否则内存泄露。

[obj1 dealloc];

这带来了一个问题。下面代码中obj2是否需要调用dealloc?

ClassA *obj1 = [[ClassA alloc] init];
ClassA *obj2 = obj1;
[obj1 hello]; //输出hello
[obj1 dealloc];
[obj2 hello]; //能够执行这一行和下一行吗?
[obj2 dealloc];

 不能,因为obj1和obj2只是指针,它们指向同一个对象,[obj1 dealloc]已经销毁这个对象了,不能再调用[obj2 hello]和[obj2 dealloc]。obj2实际上是个无效指针。

如何避免无效指针?请看下一条。

3.Objective-C采用了引用计数(ref count或者retain count)。对象的内部保存一个数字,表示被引用的次数。例如,某个对象被两个指针所指向(引用)那么它的retain count为2。需要销毁对象的时候,不直接调用dealloc,而是调用release。release会让retain count减1,只有retain count等于0,系统才会调用dealloc真正销毁这个对象。

ClassA *obj1 = [[ClassA alloc] init]; //对象生成时,retain count = 1

[obj1 release]; //release使retain count减1,retain count = 0,dealloc自动被调用,对象被销毁

我们回头看看刚刚那个无效指针的问题,把dealloc改成release解决了吗?

ClassA *obj1 = [[ClassA alloc] init]; //retain count = 1
ClassA *obj2 = obj1; //retain count = 1
[obj1 hello]; //输出hello
[obj1 release]; //retain count = 0,对象被销毁
[obj2 hello];
[obj2 release];

 [obj1 release]之后,obj2依然是个无效指针。问题依然没有解决。解决方法见下一条。

4.Objective-C指针赋值时,retain count不会自动增加,需要手动retain。

ClassA *obj1 = [[ClassA alloc] init]; //retain count = 1
ClassA *obj2 = obj1; //retain count = 1
[obj2 retain]; //retain count = 2
[obj1 hello]; //输出hello
[obj1 release]; //retain count = 2 – 1 = 1
[obj2 hello]; //输出hello
[obj2 release]; //retain count = 0,对象被销毁

问题解决!注意,如果没有调用[obj2 release],这个对象的retain count始终为1,不会被销毁,内存泄露。这样的确不会内存泄露,但似乎有点麻烦,有没有简单点的方法?见下一条。

5.Objective-C中引入了autorelease pool(自动释放对象池),在遵守一些规则的情况下,可以自动释放对象。(autorelease pool依然不是.Net/Java那种全自动的垃圾回收机制)

5.1  新生成的对象,只要调用autorelease就行了,无需再调用release!

ClassA *obj1 = [[[ClassA alloc] init] autorelease]; //retain count = 1 但无需调用release

5.2  对于存在指针赋值的情况,代码与前面类似。

ClassA *obj1 = [[[ClassA alloc] init] autorelease]; //retain count = 1
ClassA *obj2 = obj1; //retain count = 1
[obj2 retain]; //retain count = 2
[obj1 hello]; //输出hello
//对于obj1,无需调用(实际上不能调用)release
[obj2 hello]; //输出hello
[obj2 release]; //retain count = 2-1 = 1

细心的读者肯定能发现这个对象没有被销毁,何时销毁呢?谁去销毁它?(可以参考附件中的示例程序memman-with-pool.m)请看下一条。

6  autorelease pool原理剖析。(其实很简单的,一定要坚持看下去,否则还是不能理解Objective-C的内存管理机制。)

6.1 autorelease pool不是天生的,需要手动创立。只不过在新建一个iphone项目时,xcode会自动帮你写好。autorelease pool的真名是NSAutoreleasePool。

NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];

6.2 NSAutoreleasePool内部包含一个数组(NSMutableArray),用来保存声明为autorelease的所有对象。如果一个对象声明为autorelease,系统所做的工作就是把这个对象加入到这个数组中去。

ClassA *obj1 = [[[ClassA alloc] init] autorelease]; //retain count = 1,把此对象加入autorelease pool中

6.3  NSAutoreleasePool自身在销毁的时候,会遍历一遍这个数组,release数组中的每个成员。如果此时数组中成员的retain count为1,那么release之后,retain count为0,对象正式被销毁。如果此时数组中成员的retain count大于1,那么release之后,retain count大于0,此对象依然没有被销毁,内存泄露。

6.4 默认只有一个autorelease pool,通常类似于下面这个例子。

int main (int argc, const char *argv[])
{
NSAutoreleasePool *pool;
pool = [[NSAutoreleasePool alloc] init];
// do something
[pool release];
return (0);
} // main

所有标记为autorelease的对象都只有在这个pool销毁时才被销毁。如果你有大量的对象标记为autorelease,这显然不能很好的利用内存,在iphone这种内存受限的程序中是很容易造成内存不足的。例如:

int main (int argc, const char *argv[])
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
int i, j;
for (i = 0; i < 100; i++ )
{
 for (j = 0; j < 100000; j++ )
    [NSString stringWithFormat:@"1234567890"];//产生的对象是autorelease的。
}
[pool release];
return (0);
} // main

(可以参考附件中的示例程序memman-many-objs-one-pool.m,运行时通过监控工具可以发现使用的内存在急剧增加,直到pool销毁时才被释放)你需要考虑下一条。

7. Objective-C程序中可以嵌套创建多个autorelease pool。在需要大量创建局部变量的时候,可以创建内嵌的autorelease pool来及时释放内存。(感谢网友hhyytt和neogui的提醒,某些情况下,系统会自动创建autorelease pool, 请参见第四章)

int main (int argc, const char *argv[])

{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
int i, j;
for (i = 0; i < 100; i++ )
{
 NSAutoreleasePool *loopPool = [[NSAutoreleasePool alloc] init];
 for (j = 0; j < 100000; j++ )
    [NSString stringWithFormat:@"1234567890"];//产生的对象是autorelease的。
 [loopPool release];
}
[pool release];
return (0);
} // main

 

VN:F [1.9.22_1171]
Rating: 9.0/10 (2 votes cast)
VN:F [1.9.22_1171]
Rating: +1 (from 1 vote)