簡體   English   中英

如何使用塊完成處理程序實現類方法

[英]How to implement a class method with a block completion handler

我正在嘗試實現類似於即棄類的方法

+ (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];
}

基本上,我將對象的所有權傳遞給自身,並將其釋放到處理程序中。 有什么問題嗎?

此代碼有很多錯誤。 除了塊屬性需要copy 您不應該進行[self retain]; [self release]; (ps在錯誤的情況下錯過了[self release] )。 這完全違反了內存管理規則。 如果您做正確的事,它們是完全不必要的。 Cocoa中的內存管理完全是本地的-函數或方法只需要關心它的作用,而不需要其他代碼的作用。 init沒有理由進行[self retain] ,也不必“擔心”任何其他代碼的作用。 期。

然后_completionHandler = handler; _identifiers = identifiers; _completionHandler = handler; _identifiers = identifiers; 錯了。 如果將塊存儲在實例變量中,則需要復制該塊; 並且該集需要保留或復制。 你需要做的要么 _completionHandler = [handler copy]; _identifiers = [identifiers retain]; _completionHandler = [handler copy]; _identifiers = [identifiers retain]; 或者使用setter self.completionHandler = handler; self.identifiers = identifiers; self.completionHandler = handler; self.identifiers = identifiers;

這樣,就沒有“保留周期”的問題。 保留循環需要一個循環-A保留B,B保留A。塊保留self ,但是self保留塊嗎? 我在任何地方都看不到。 您只是在此塊上調用另一個類的類方法。 因此,您不應該做薄弱的參考。 無論如何,弱引用是不正確的,因為不能保證在塊執行時當前對象將是有效的。

似乎是您(錯誤地)完成了整個[self retain]事情,都是為了處理您(也是錯誤地)不允許該塊保留self的事實,它應該這樣做。 只需擺脫這些弱參考資料,再擺脫[self retain]資料,它就不僅會遵循內存管理規則,變得更加健壯,而且看起來更簡潔,更容易理解。

@property (nonatomic, copy) StuffInfoDownloaderCompletionBlock
completionHandler;

然后初始化:

self.completionHandler = handler;

如果您以前沒有復制過塊,則永遠不要保留它,這是沒有道理的。

順便說說

 if ((self = [super init])) {
    /* initialization stuff*/
    }


 return self;

似乎您的代碼有很多retainCycle缺陷設計

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM