IOS 5 ARC机制 (三)

使用在函数参数转换的从属关键词

当在函数调用的参数中使用Objective-C和基础核心实例的转换的时候,你需要告诉编译关于这个传入参数的所属信息。这些基础核心实例的所属规则定义在基础核心内存管理规则中(参考 Memory Management Programming Guide for Core Foundation);Objective-C实例的规则定义在Advanced Memory Management Programming Guide.

在下面的代码片段中,传入函数的CGGradientCreateWithColors 的数组是需要转换的。byarrayWithObjects:函数返回的实例所属没有传入参数,转换关键词使用__bridge.

NSArray *colors = [NSArray arrayWithObjects:[[UIColor darkGrayColor] CGColor],[[UIColor lightGrayColor] CGColor], nil];CGGradientRef gradient = CGGradientCreateWithColors(colorSpace, (__bridge CFArrayRef)colors, locations);

下例演示了函数中的代码片段的情况,注意所有核心内存管理函数都是遵循基础核心内存管理规则的。

- (void)drawRect:(CGRect)rect {CGContextRef ctx = UIGraphicsGetCurrentContext();CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceGray();CGFloat locations[2] = {0.0, 1.0};NSArray *colors = [NSArray arrayWithObjects:[[UIColor darkGrayColor] CGColor],[[UIColor lightGrayColor] CGColor], nil];CGGradientRef gradient = CGGradientCreateWithColors(colorSpace, (__bridge CFArrayRef)colors, locations);CGColorSpaceRelease(colorSpace); // Release owned Core Foundation object.CGPoint startPoint = CGPointMake(0.0, 0.0);CGPoint endPoint = CGPointMake(CGRectGetMaxX(self.bounds), CGRectGetMaxY(self.bounds));CGContextDrawLinearGradient(ctx, gradient, startPoint, endPoint,kCGGradientDrawsBeforeStartLocation | kCGGradientDrawsAfterEndLocation);CGGradientRelease(gradient); // Release owned Core Foundation object.}

这个问题的细节在 “Managing Toll-Free Bridging”里面讨论。

转换旧工程的要点

在扩展旧工程的时候,你需要注意下面事项.

你不能调用retain, release,或者 autorelease.

同样,下面的代码也不能写:

while ([x retainCount]) { [x release]; }
你不能调用dealloc.

一般情况下,在单例模式下,或者需要替换实例的时候,可能需要在init函数里面调用dealloc函数。对于单例模式,你可以使用共享模式来替代。因为后者在init里面不需要调用dealloc,在你从新对self赋值的时候,原内存就被释放了。

你不用使用NSAutoreleasePool对象

新的@autoreleasepool{}结构是作为一个替代。它比原先的NSAutoreleasePool快六倍。@autoreleasepool同样在手动管理内存的方式下能够工作。

在init方法中,ARC要求把[super init]赋值给self。

下面的代码在ARC模式下是不合法的。

[super init];

简单的改成下面这个样就可以了:

self = [super init];

一般还需要检查返回值:

self = [super init];if (self) {...
你不能实现自己的retain和release方法。

实现自己的retain或release方法会破坏弱指针,这里有一些理由阻止你这样做:

  • 性能.

    请不要实现这些函数,因为在NSObject中的实现快多了,如果你发现问题,那么需要改掉这些问题,而不是再次实现这些函数。

  • 为了实现弱指针To implement a custom weak pointer system.

    使用__weak来替代这些函数的实现.

  • 为了实现单例模式。

    使用共享模式。或者,使用类级别函数,这样根本不需要申请实例。

如果你发现不得不实现retain或者release函数,那么请在类中实现下面的函数:

-(BOOL)supportsWeakPointers { return NO; }

上面的函数阻止为你的类生成弱指针。不过还是强烈建议你使用其他的方式来避免实现这些函数。

不能在C语言的结构中使用strong ids。

比如,下面的代码不能被编译:

struct X { id x; float y; };

因为x并定义强引用,那么编译器就不能为它生成按照的管理代码。例如,如果x以及被赋值,那么在这个结构的指针被free前,必须先释放这些x指向的内存,但是由于是ARC模式,所以这些内存就被泄漏了,所以在C语言的结构中,ARC禁止使用强指针,下面是可能的解决方案:

  1. 使用类来代替结构。

    这是最好的方式。

  2. 如果在使用类有性能问题(比如你需要一个很大的结构的数组),那么可以使用void*来代替。

    这需要显式的转换,下面会有讨论。

  3. 把这个变量用__unsafe_unretained修饰。

    这个会对下面的情况会有帮助:

    struct x { NSString *S; int X; } StaticArray[] = {@"foo", 42,@"bar, 97,...};

    你可以这样定义结构:

    struct x { __unsafe_unretained NSString *S; int X; }

    这样的写法可能会有很大的问题,如果在指针里面的实例被释放了。but it is very useful for things that are known to be around forever like constant string literals.

你不能直接进行id和void *的转换(包括核心功能中的类型)。
posted @ 2012-11-22 11:56  GreyWolf  阅读(219)  评论(0编辑  收藏  举报