2012-04-23 6 views
2

注:This similar SO questionは、同じクラスを構築する方法について話しますが、クラスの使用に関連するメモリ管理の問題には対処しません。カスタムNSURLConnectionラッパーオブジェクトの所有権を保持する必要はありますか? (ARC環境で)

私はsendAsynchronousRequest:queue:completionHandler:を使用したいと思いますが、iOS 4.2をサポートする必要があります。

  • :私は(私はARCのメモリ管理にいるよ)このクラスの使用方法について質問があり

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

    :したがって、私はNSURLConnectionを使用して、素敵なインターフェイスを生成JCURLRequestというカスタムクラスを作成しました私は自分のJCURLRequestオブジェクトを作成しますが、そのオブジェクトへの参照を保持する必要がありますか?それとも、「火をつけて忘れることはできますか?

注:オブジェクトへのポインタがある場合、オブジェクトへのポインタがない場合は、次の自動リリースで解放されます。プール。

このように、私が知りたい - 私は同じようにそれを呼び出すことができます(1)またはI(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

+0

また、ブロック内で 'self'を参照すると、ブロックは保持されます。 – Joe

+0

@bearMountain警告を抑制する別の方法は、式の結果を保存しないことです! (私が上に示したように)。変数を使用しない場合は、変数を格納する必要はありません。 – joerick

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を残す場合

はリクエストも終了する前に割り当てが解除されます AsyncObjectを意味し Deallocated!でプリントアウトする最初の事をコメントアウト。今度は ivarのコメントを外すと、ブロックが適切な値を正しく保持しているので、 Deallocated!が最後になるようになりました。しかし、発送が selfを参照して _weakを使用した場合、これは壊れている可能性があります。

+0

は、あなたの答えをいただき、ありがとうございます。 joerickが指摘したように、 'NSURLConnection'はデリゲートを保持しています。しかし、あなたの答えはまだ私に大きな新たな洞察力を与えました。オブジェクトのライフサイクルを追跡するために ' - (void)dealloc'を使うのは非常に便利です。 ARCに変換すると、 'retain'、' release'、 'dealloc'をすべて破棄しましたが、' dealloc'を実装できることを覚えておくと非常に便利です! – bearMountain