博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
ARC Best Practices[转]
阅读量:6982 次
发布时间:2019-06-27

本文共 8100 字,大约阅读时间需要 27 分钟。

Some optional backstory:

  • The relevant documentation is: 
  • Mike Ash also has a ARC great writeup in one of his .
  • The deep technical documentation lives at the  of the LLVM project.

The advice here assumes you are using iOS 5, not 4. In practice, weak pointers are such an important tool in ARC, that I don’t recommend using ARC in iOS 4.

General

  • scalar ivar properties should use assign.

    @property (nonatomic, assign) int scalarInt;    @property (nonatomic, assign) CGFloat scalarFloat;    @property (nonatomic, assign) CGPoint scalarStruct;
  • object ivar properties that need to be retained or reference “down” the object hierarchy should use strong.

    @property (nonatomic, strong) id childObject;
  • object ivar properties that reference “up” the object hierarchy should use weak. Additionally, when referencing “off” the object graph weak is the safest.

    @property (nonatomic, weak) id parentObject;    @property (nonatomic, weak) NSObject 
    *delegate;
  • Blocks should still use copy

    @property (nonatomic, copy) SomeBlockType someBlock;
  • In dealloc:

    • remove observers
    • unregister for notifications
    • set any delegates to nil
    • invalidate any timers
  • IBOutlets should be weak except for top-level IBOutlets, which should bestrong.

Bridging

From the documentation:

id my_id;CFStringRef my_cfref;NSString   *a = (__bridge NSString*)my_cfref;     // Noop cast.CFStringRef b = (__bridge CFStringRef)my_id;      // Noop cast.NSString   *c = (__bridge_transfer NSString*)my_cfref; // -1 on the CFRefCFStringRef d = (__bridge_retained CFStringRef)my_id;  // returned CFRef +1

Translated from nerd-speak into slightly-less-nerd-speakish:

  • __bridge is a noop (with respect to memory management)
  • __bridge_transfer is for changing CF references to Objective C objects. ARC will release the ObjC object for you. Make sure that the CFRef has +1 retain count.
  • __bridge_retained is for changing Objective C objects to CF references. This will effective give you a CF reference with a +1 retain count. You are responsible for calling CFRelease on the CFRef at some point in the future.

NSError

The typical NSError is a little bit tricky. Typical Cocoa convention is that they are implemented via out-parameters (aka indirect pointers).

In ARC, out-parameters are by default __autoreleasing and should be implemented like this:

- (BOOL)performWithError:(__autoreleasing NSError **)error{// ... some error occurs ...if (error){// write to the out-parameter, ARC will autorelease it*error = [[NSError alloc] initWithDomain:@""code:-1userInfo:nil];return NO;}else{return YES;}}

When using an out-parameter, you will usually use __autoreleasing on your *errorobject like so:

NSError __autoreleasing *error = error;BOOL OK = [myObject performOperationWithError:&error];if (!OK){// handle the error.}

If you forget the __autoreleasing, the compiler will simply insert a temporary, intermediate autoreleasing object for you. This was a compromise made under the oppressive regime of backwards compatibility.

@autoreleasepool

Use @autoreleasepool inside loops that:

  • iterate many, many times
  • create large numbers of temporary objects

    // If someArray is huge    for (id obj in someArray)    {    @autoreleasepool    {    // or you are creating lots    // of temporary objects here...    }    }

Creating and destroying autorelease pools using the @autoreleasepool directive is cheaper than a blue light special. Don’t worry about doing it inside the loop. If you are super-paranoid, at least check the profiler first.

Blocks

In general, blocks just work. There are a few exceptions however.

When adding block pointers to a collection, you need to copy them first.

someBlockType someBlock = ^{NSLog(@"hi");};[someArray addObject:[someBlock copy]];

Retain cycles are somewhat dangerous with blocks. You may have seen this warning:

warning: capturing 'self' strongly in thisblock is likely to lead to a retain cycle[-Warc-retain-cycles,4]SomeBlockType someBlock = ^{[self someMethod];};

The reason is that someBlock is strongly held by self and the block will “capture” and retain self when/if the block is copied to the heap.

In a less obvious manifestation of the same potential retain cycle, any ivar you use will also capture the parent object:

// The following block will retain "self"SomeBlockType someBlock = ^{BOOL isDone = _isDone;  // _isDone is an ivar of self};

The safer, but loquacious workaround is to use a weakSelf:

__weak SomeObjectClass *weakSelf = self;SomeBlockType someBlock = ^{SomeObjectClass *strongSelf = weakSelf;if (strongSelf == nil){// The original self doesn't exist anymore.// Ignore, notify or otherwise handle this case.}[self someMethod];};

Sometimes, you need to take care to avoid retain cycles with arbitrary objects: IfsomeObject will ever strongly hold onto the block that uses someObject, you needweakSomeObject to break the cycle.

SomeObjectClass *someObject = ...__weak SomeObjectClass *weakSomeObject = someObject;someObject.completionHandler = ^{SomeObjectClass *strongSomeObject = weakSomeObject;if (strongSomeObject == nil){// The original someObject doesn't exist anymore.// Ignore, notify or otherwise handle this case.}// okay, NOW we can do something with someObject[strongSomeObject someMethod];};

Accessing CGThings from NSThings or UIThings

UIColor *redColor = [UIColor redColor];CGColorRef redRef = redColor.CGColor;// do some stuff with redRef.

The above example has some very subtle problems. When you create redRef, if redColor is never used again, then redColor is destroyed right after the comment.

The problem is that redColor “owns” redRef, and when redRef is accessed, it may or may not be a colorRef anymore. Even worse, is that this type of error rarely shows up on the simulator. It’s more likely to occur when used on a device with lower working memory, like the original iPad.

There are a couple of workarounds. Essentially, you just want to keep redColor alive while you use redRef.

One very easy way to accomplish this is to use __autoreleasing.

UIColor * __autoreleasing redColor = [UIColor redColor];CGColorRef redRef = redColor.CGColor;

Now, redColor isn’t destroyed until some indeterminate time later, well after the method returns. We can safely use redRef in the scope of our method.

Another way is to retain the redRef:

UIColor *redColor = [UIColor redColor];CGColorRef redRef = CFRetain(redColor.CGColor);// use redRef and when done release it:CFRelease(redRef)

It’s important to note that you need CFRetain() on the same line where you use redColor.CGColor. redColor is effectively destroyed after the last time you use it. The following will NOT work:

UIColor *redColor = [UIColor redColor];CGColorRef redRef = redColor.CGColor; // redColor is released right after this...CFRetain(redRef);  // This may crash......

One interesting note on the line marked “This may crash” above. In my experience, it doesn’t crash very often in the simulator, but does tend to crash repeatedly on the device. Caveat Developor.

The Big Nerd Ranch has a very deep dive into this issue:

Singletons

Only incidentally related to ARC. There is a proliferation of home grown singleton implementations (many of which unnecessarily override retain and release).

These should all be replaced with the following:

+ (MyClass *)singleton{static MyClass *sharedMyClass = nil;static dispatch_once_t once = 0;dispatch_once(&once, ^{sharedMyClass = [[self alloc] init];});return sharedMyClass;}

Every now and then you need the ability to destroy a singleton.

If you are using this for anything but UnitTests, you probably should not be using a singleton.

// declare the static variable outside of the singleton methodstatic MyClass *__sharedMyClass = nil;+ (MyClass *)singleton{static dispatch_once_t once = 0;dispatch_once(&once, ^{__sharedMyClass = [[self alloc] init];});return __sharedMyClass;}// For use by test frameworks only!- (void)destroyAndRecreateSingleton{__sharedMyClass = [[self alloc] init];}
欢迎加群互相学习,共同进步。QQ群:iOS: 58099570 | Android: 330987132 | Go:217696290 | Python:336880185 | 做人要厚道,转载请注明出处!http://www.cnblogs.com/sunshine-anycall/archive/2012/08/30/2664626.html
你可能感兴趣的文章
我的友情链接
查看>>
我的友情链接
查看>>
xmlUtil 解析 创建
查看>>
我的友情链接
查看>>
linux 命令(3)echo
查看>>
Nginx基础入门之nginx基础配置项介绍(2)
查看>>
一次详细全面的***报告
查看>>
c# 三种异步编程模型EAP(*)、 APM(*)和 TPL
查看>>
deepin-安装问题:unable to find a medium containing a live file
查看>>
用 Hasor 谈一谈MVC设计模式
查看>>
IE 条件注释
查看>>
Windows热键注册(反汇编方法 查看win32api 原理)
查看>>
UNREFERENCED_PARAMETER的作用
查看>>
PHP计算表达式-栈
查看>>
sysbench OLTP基准测试
查看>>
IBATIS中关于iterate"$"与"#"的应用
查看>>
centos -bash: vim: command not found
查看>>
为什么要将对象序列化
查看>>
新增网址/网页 截图api[增加安全防护本接口已停用]源码可下载
查看>>
SpringMVC+Hibernate +MySql+ EasyUI实现POI导出Excel(二)
查看>>