objective-c - 如何使用 block 完成处理程序实现类方法

标签 objective-c ios asynchronous objective-c-blocks

我正在尝试实现类似于“即发即忘”的类方法

+ (void)sendAsynchronousRequest:(NSURLRequest *)request queue:(NSOperationQueue *)queue completionHandler:(void (^)(NSURLResponse*, NSData*, NSError*))handler

NSURLConnection中,但我对内存管理有点困惑(我目前没有使用ARC)。

我当前的代码如下:

@interface StuffInfoDownloader() <UIAlertViewDelegate>

typedef void (^StuffInfoDownloaderCompletionBlock)(NSArray *stuffs);

- (id)initStuffsWithIdentifiers:(NSSet *)identifiers
         completionHandler:(void (^)(NSArray *stuffs))handler;

@property (retain, nonatomic) StuffInfoDownloaderCompletionBlock completionHandler;
@property (retain, nonatomic) NSSet *identifiers;

@end

@implementation StuffInfoDownloader

@synthesize completionHandler = _completionHandler;
@synthesize identifiers = _identifiers;

+ (void)loadAsynchronouslyWithIdentifiers:(NSSet *)identifiers
                    completionHandler:(void (^)(NSArray *stuffs))handler
{
    StuffInfoDownloader *downloader = [[StuffInfoDownloader alloc] initStuffsWithIdentifiers:identifiers completionHandler:handler];

    [downloader downloadStuffs];
    [downloader release]; // will retain itself
}

- (id)initStuffsWithIdentifiers:(NSSet *)identifiers
          completionHandler:(void (^)(NSArray *stuffs))handler
{

    if (!(self = [super init])) {
        return nil;
    }

    [self retain];

    _completionHandler = handler;
    _identifiers = identifiers;

    return self;
}

- (void)downloadStuffs
{
    __block StuffInfoDownloader *me = self; // avoid reference cycle between self and the block
    [StuffsConnection loadAsynchronouslyWithIdentifiers:self.identifiers completionHandler:
    ^(NSArray *stuffs, NSError *error) {
         if(error) {
             UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Connection Failed."
                                                         message:@"TODO do localised string"
                                                        delegate:self cancelButtonTitle:@"OK"
                                               otherButtonTitles:nil, nil];
             [alert show];
             [alert release];
         } else {
             me.completionHandler(stuffs);
             [self release];
         }
    }];
}

#pragma mark UIAlertViewDelegate

- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
#pragma unused(alertView, buttonIndex)
    // try again
    [self downloadStuffs];
}

- (void)dealloc
{
    [_completionHandler release];
    [_identifiers release];
    [super dealloc];
}

基本上,我将对象的所有权传递给其自身,并在处理程序中释放它。有什么问题吗?

最佳答案

这段代码有很多问题。除了需要复制 block 属性之外。您不应该执行 [self keep];[self release]; (另外,您在错误中错过了 [self release]案件)。这完全违反了内存管理规则。如果你做对了,它们是完全没有必要的。 Cocoa 中的内存管理完全是本地的——函数或方法只需要关心它做什么,而不需要关心任何其他代码做什么。 init 没有理由执行[self keep],并且不必“担心”任何其他代码的作用。期间。

然后_completionHandler = handler; _identifiers = 标识符; 是错误的。如果要将 block 存储在实例变量中,则需要复制该 block ;并且该集合需要保留或复制。您需要执行任一 _completionHandler = [handler copy]; _identifiers = [identifiers keep]; 或使用 setter self.completionHandler = handler; self.identifiers = 标识符;.

那么,就不存在“保留周期”的问题了。一个保留循环需要一个循环——A保留B,B保留A。 block 保留self,但是self保留 block 吗?我在任何地方都没有看到这一点。您只需在此 block 上调用另一个类的类方法即可。所以你不应该做弱引用。无论如何,弱引用都是不正确的,因为不能保证当前对象在 block 执行时有效。

看来你(错误地)做了整个[self keep]事情,所有这些都是为了处理你(也是错误地)不允许 block 保留的事实self,正如它应该的那样。只要去掉这个弱引用的东西,去掉[self keep]的东西,那么它不仅会遵循内存管理规则,更加健壮,而且看起来更干净,更简单,并且更容易理解。

关于objective-c - 如何使用 block 完成处理程序实现类方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12837027/

相关文章:

objective-c - Foundation 可以告诉我 Objective-C 方法是否需要特殊结构返回吗?

iphone - Xcode 4.6 构建、运行并立即完成(模拟器 iOS 6.1)

ios/objective-c : Create Segue from Textview to View Controller in Storyboard

java - ThreadPoolExecutor 中的核心池大小与最大池大小

asynchronous - 在 Dart 中 Future.wait 真的是异步的吗?

ios - 如何在 uiview 中添加边框?

ios - Xcode 5 使用不同的图像取决于是否使用 iOS 7 或更低版本

iphone - 如何打印 NSMutableURLRequest?

iOS 11 使用 ATS 从 HTTP 加载图像

javascript - 异步函数和 Readline 使用