2012-10-11 26 views
0

我試圖實現發射後不管類類似的方法來如何實現一個類的方法與塊完成處理

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

基本上,我傳遞對象的所有權本身,並在處理程序釋放出來。有什麼問題呢?

+0

它工作嗎?如果是這樣,我看起來很好。除了我真的不會那麼保留自己的事情。如果你切換到使用ARC(你應該),那麼這根本就不起作用。做一個類似的事情,你可以有一個強大的財產來保持自我。這更清楚發生了什麼,並且稍後更容易調試,IMO。 – mattjgalloway

回答

1

有這麼多事情不對的代碼。除了塊屬性需要copy。你不應該這樣做[self retain];[self release];(p.s.你在錯誤情況下錯過了[self release])。這完全違背了內存管理規則。如果你做正確的事情,他們完全沒有必要。 Cocoa中的內存管理完全是本地化的 - 一個功能或方法只需要關心什麼這樣做,而不是其他任何代碼。 init沒有理由做[self retain],並且不必擔心其他代碼的作用。期。

然後_completionHandler = handler; _identifiers = identifiers;是錯誤的。如果要將塊存儲在實例變量中,則需要複製該塊;並且該組需要被保留或複製。您需要執行或者_completionHandler = [handler copy]; _identifiers = [identifiers retain];或使用設置器self.completionHandler = handler; self.identifiers = identifiers;

然後,沒有「保留週期」的問題。保留週期需要一個循環--A保留B,B保留A.該塊保留self,但self保留該塊嗎?我在任何地方都看不到。您只需調用此塊上另一個類的類方法。所以你不應該這樣做。無論如何,弱引用是不正確的,因爲不能保證當前對象在塊執行時是有效的。

看來你(錯誤地)做了整個[self retain]的事情,所有這些都是爲了處理你(也錯誤地)不允許該塊保留self的事實,因爲它應該如此。只要擺脫這種薄弱的參考資料,並擺脫這些東西,然後它不僅會遵循內存管理規則,更健壯,而且看起來更乾淨,更簡單,更容易理解。

0
@property (nonatomic, copy) StuffInfoDownloaderCompletionBlock 
completionHandler; 

然後在初始化:

self.completionHandler = handler; 

如果u以前沒有把它抄了你不應該保留塊,那沒有意義。

順便說

看來你的代碼有很多retainCycle缺陷設計

相關問題