2012-04-23 65 views
2

注意:This similar SO question討論如何構建相同的類,但未解決與使用該類有關的內存管理問題。我想用sendAsynchronousRequest:queue:completionHandler:,但是我需要支持iOS 4.2。因此,我創建了一個名爲JCURLRequest的自定義類使用NSURLConnection並生成漂亮的界面:我是否需要保留我的自定義NSURLConnection包裝對象的所有權? (在ARC環境中)

- (void)sendRequest:(NSURLRequest *)request 
    responseHandler:(JCURLResponseHandler)responseHandler; 

我有一個關於使用這個類(我在ARC內存管理)問題:

  • 當我創建我的JCURLRequest對象,我需要保留對該對象的引用嗎?或者我可以「開火併忘記」嗎?

注意:我理解ARC的基本知識 - 如果有一個指向對象的指針,它將保持活動狀態,如果沒有更多指向對象的指針,它將在下一次自動釋放時釋放池。

因此,我想知道 - 我可以這樣調用它(1)或者我需要使用(2)

(1)

JCURLRequest *jcURLRequest = [[JCURLRequest alloc] init]; 
[jcURLRequest sendRequest:myRequest 
      responseHandler:^(NSData *data, NSError *error) { ... }]; 
// Assuming I don't maintain a reference to jcURLRequest after this 

(2)

// Assume @property (strong) JCURLRequest *jcURLRequest; 
//  @synthesize jcURLRequest = _jcURLRequest; 
self.jcURLRequest = [[JCURLRequest alloc] init]; 
[self.jcURLRequest sendRequest:myRequest 
      responseHandler:^(NSData *data, NSError *error) { ... }]; 

NSURLConnection使用異步回調,所以我的想法是我必須使用(2)。這是因爲 - 當代理回調「回調」時,jcURLRequest實例可能已經在自動發佈池中清除了。

雖然我很困惑,因爲我已經用(1)進行了測試,並且它「看起來」工作正常。但是,我的想法是,也許這只是巧合,它的工作 - 即。真的沒有更多有效的指向jcURLRequest對象的指針,但是iOS並沒有得到解除分配的指示。

以下是完整JCURLRequest類參考

// JCURLRequest.h 
#import <Foundation/Foundation.h> 

typedef void (^JCURLResponseHandler) (NSData *data, NSError *error); 

@interface JCURLRequest : NSObject 
- (void)sendRequest:(NSURLRequest *)request responseHandler:(JCURLResponseHandler)responseHandler; 
@end 



// JCURLRequest.m 
#import "JCURLRequest.h" 

@interface JCURLRequest() 
{ 
    JCURLResponseHandler responseHandler; 
} 
@property (strong, nonatomic) NSMutableData *responseData; 
@end 

@implementation JCURLRequest 
@synthesize responseData = _responseData; 


#pragma mark - Public API 

- (void)sendRequest:(NSURLRequest *)request responseHandler:(JCURLResponseHandler)handler 
{ 
    responseHandler = [handler copy]; 
    dispatch_async(dispatch_get_main_queue(), ^{ 
     __unused NSURLConnection *connectionNotNeeded = [[NSURLConnection alloc] initWithRequest:request delegate:self]; 
    }); 
} 


#pragma mark - Private API 

- (NSMutableData *)responseData 
{ 
    if (!_responseData) 
    { 
     _responseData = _responseData = [[NSMutableData alloc] initWithLength:0]; 
    } 

    return _responseData; 
} 


#pragma mark - URL Connection Methods 

- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response 
{ 
    [self.responseData setLength:0]; 
} 

- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data 
{ 
    [self.responseData appendData:data]; 
} 

- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error 
{ 
    responseHandler(nil, error); 
} 

- (void)connectionDidFinishLoading:(NSURLConnection *)connection 
{  
    responseHandler([NSData dataWithData:self.responseData], nil); 
} 

@end 

回答

2

NSURLConnection在連接處於活動狀態時保留其委託和自身。所以你的解決方案並不是巧合。

我無法找到任何這的官方消息,但它已經證實非官方這裏SO:

+0

不知道關於NSURLConnection - 謝謝,這非常有幫助。我發現在[特殊考慮](http://developer.apple.com/library/mac/#documentation/Cocoa/Reference/Foundation/Classes/NSURLConnection_Class/Reference/Reference.html#//apple_ref/doc/uid/ 20001697-BAJDDIDG)你會看到這個官方文檔。關於'__unused',我用它來抑制'Expression result unused'的警告。你知道另一種方法來抑制這種警告嗎? – bearMountain 2012-04-24 16:54:19

+0

同時在塊內引用'self'會導致它被保留。 – Joe 2012-04-24 17:19:47

+0

@bearMountain另一種抑制警告的方法是不存儲表達式結果! (如上所示)。如果您不打算使用該變量,則不需要存儲它。 – joerick 2012-04-25 08:36:11

2

我會建議保留JCURLRequest是安全的和正確的。看看下面的代碼,例如:

@interface AsyncObject : NSObject 
{ 
    BOOL ivar; 
} 
-(void)sendRequest:(void(^)()) callback; 
@end 

@implementation AsyncObject 
-(void)sendRequest:(void (^)())callback 
{ 
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ 
     NSLog(@"Starting Long Async Task"); 
     sleep(15); 
     //ivar = YES; 
     NSLog(@"Calling Callback"); 
     callback(); 
    }); 
} 
-(void)dealloc 
{ 
    NSLog(@"Deallocated!"); 
} 
@end 

    ... 
    [[[AsyncObject alloc] init] sendRequest:^{ NSLog(@"Called Back"); }]; 

如果你離開ivar註釋掉打印出是Deallocated!這意味着AsyncObject被釋放的要求,甚至完成之前的第一件事。現在,如果您取消註釋ivar,則Deallocated!現在應該是最後一個,因爲該塊可以正確保留正確的值。但是,如果派遣使用了對self的引用,則可能會損壞。

__weak AsyncObject *self_ = self; 
    ... //Inside gcd async method 
    self_->ivar = YES; //This will break 
+0

謝謝您的回答。事實證明,正如joerick所指出的,'NSURLConnection'保留了它的委託。但是,你的回答仍然給了我很好的新見解。如果我不確定它,使用' - (void)dealloc'來跟蹤對象的生命週期是非常有用的。我想,一旦我轉換爲ARC,我放棄了所有'retain','release','dealloc',但記住我仍然可以實現'dealloc'! – bearMountain 2012-04-24 17:13:46

相關問題