2

注:この同様の SO の質問では、同じクラスを構築する方法について説明していますが、クラスの使用に関連するメモリ管理の問題には対処していません。

を使用したいのですがsendAsynchronousRequest:queue:completionHandler:、iOS 4.2 をサポートする必要があります。したがって、 Nice インターフェースJCURLRequestを使用および生成するというカスタム クラスを作成しました。NSURLConnection

- (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
4

2 に答える 2

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コメントを外すと、ブロックが正しい値を適切に保持するため、ivarthenが最後になります。ただし、ディスパッチが への参照をDeallocated!使用した場合、これは壊れる可能性があります。_weakself

__weak AsyncObject *self_ = self;
    ... //Inside gcd async method
    self_->ivar = YES; //This will break
于 2012-04-23T20:31:19.887 に答える
2

NSURLConnection は、接続が有効な間、デリゲートとそれ自体を保持します。したがって、ソリューションが機能するのは偶然ではありません。

これに関する公式の情報源は見つかりませんが、SOで非公式に確認されています:

于 2012-04-23T21:09:35.900 に答える