简体   繁体   中英

Objective-C, ARC: Is it correct to use __weak arguments?

Here's a little example of using weak arguments:

@interface MYTestObject : NSObject

@end

@implementation MYTestObject {
   void(^_block)(void);
}

- (void)dealloc {
   NSLog(@"DEALLOC!");
}

- (id)init {
   if (self = [super init]) {
      [self doSomethingWithObject:self];
   }
   return self;
}

- (void)doSomethingWithObject:(id __weak /* <- weak argument! */)obj {
   _block = ^{
      NSLog(@"%p", obj);
   };
}

@end

And it works: -dealloc is called! Also, if you remove __weak you'll get a retain-cycle and it's absolutely correct.

Wonder, if that's just a side-effect and it's completely unsafe to use weak arguments? Or is it a specified behavior and I'm just a bad google-user?

Two observations:

  1. I'd be inclined to make a local __weak reference within doSomethingWithObject , rather than make it a __weak argument as illustrated in Avoid Strong Reference Cycles when Capturing self .

    I don't think that it is, as you asked, "completely unsafe to use weak arguments." But if nothing else, it's the more common pattern to have a local __weak variable and strikes me as more appropriate as an implementation detail of doSomethingWithObject rather than part of the method's public interface.

  2. I'd also make block a property with the copy memory qualifier. As the docs say

    You should specify copy as the property attribute, because a block needs to be copied to keep track of its captured state outside of the original scope. This isn't something you need to worry about when using Automatic Reference Counting, as it will happen automatically, but it's best practice for the property attribute to show the resultant behavior.

Thus:

@interface MYTestObject : NSObject
@property (nonatomic, copy) void(^block)(void);
@end

@implementation MYTestObject

- (void)dealloc {
    NSLog(@"DEALLOC!");
}

- (id)init {
    if (self = [super init]) {
        [self doSomethingWithObject:self];
    }
    return self;
}

- (void)doSomethingWithObject:(MYTestObject *)obj { 

    typeof(obj) __weak weakObj = obj;

    self.block = ^{
        NSLog(@"%p", weakObj);
    };
}

@end

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM