1

私は何が起こっているのかを知っていると確信していますが、それを防ぐ良い方法があるかどうか知りたいです。

基本的に、コアデータストアから何かを検索するクラスメソッドがあり、何も存在しない場合は、Webサーバーからそれをフェッチしようとします。コアデータのルックアップとリクエストは、管理対象オブジェクトコンテキストperformBlockメソッドで実行されます。

次のコードブロックがあります。

[context performBlock:^{
    __block NSError *error;
    NSFetchRequest *request = [[NSFetchRequest alloc] initWithEntityName:NSStringFromClass([self class])];
    [request setSortDescriptors:@[[[NSSortDescriptor alloc] initWithKey:key ascending:asc selector:@selector(caseInsensitiveCompare:)]]];

    NSFetchedResultsController *controller = [[NSFetchedResultsController alloc] initWithFetchRequest:request
                                                                                 managedObjectContext:context
                                                                                   sectionNameKeyPath:keyPath
                                                                                            cacheName:nil];

    [controller performFetch:&error];

    if (!controller.fetchedObjects || controller.fetchedObjects.count == 0) {
        // Nothing found or an error, query the server instead
                NSString *url = [NSString stringWithFormat:@"%@%@", kMP_BASE_API_URL, [self baseURL]];
        MPRequest *objRequest = [MPRequest requestWithURL:url];

        [objRequest setRequestMethod:@"GET"];
        [MPUser signRequest:objRequest];

        [objRequest submit:^(MPResponse *resp, NSError *err) {
            if (err) {
                block(nil, err);
            } else {
                NSArray *objects = [self createListWithResponse:resp];
                         objects = [MPModel saveAllLocally:objects forEntityName:NSStringFromClass([self class])];
                [controller performFetch:&error];
                block(controller, nil);
            }

        }];
    } else {
        // Great, we found something :)
        block (controller, nil);
    }
}];

何が起こっているのかというと、MPRequestオブジェクトが作成されて起動されますが、submitメソッドは非同期要求をトリガーするため、ほぼ瞬時に戻ります。その後、ARCがMPRequestオブジェクトを解放していると思います。リクエストが実行されると、ARCがリリースしたため、内部リクエストオブジェクトのデリゲートは存在しなくなります(MPRequestオブジェクトは、それが持つ内部リクエストのデリゲートです)。このため、submitメソッドが提供されているブロックは呼び出されません。

リクエストを同期せずにARCがこれを行うのを防ぐ方法はありますか?

編集

submit方法はMPRequest次のようになります

_completionBlock = block;
   _responseData = [[NSMutableData alloc] init];

[self prepareRequest];

[self prepareRequestHeaders];
_connection = [[NSURLConnection alloc] initWithRequest:_urlRequest
                                              delegate:self];
[self requestStarted];
4

2 に答える 2

1

接続MPRequestの実行中、オブジェクトはそれ自体を存続させる必要があります。これを行う最も簡単な方法は、接続の開始時にそれ自体を保持し、完了ブロックを呼び出した後にそれ自体を解放することです。ARCでは、これを行う最も簡単な方法は次のとおりです。

CFRetain((__bridge CFTypeRef)self);

CFRelease((__bridge CFTypeRef)self);

概念的には、実行ループは要求を存続させます。これがNSURLConnection動作方法です。ただし、MPRequestは実際には実行ループにアタッチされていないため、単なるラッパーでNSURLConnectionあり、同じ期間存続させるためにいくつかの作業を行う必要があります。

またNSURLConnection、適切な実行ループに追加する必要があることに注意してください。便利なメソッドはそれを現在のスレッドの実行ループに追加しますが、バックグラウンドキューにいる場合、それは機能しません。あなたは次のようなものを使うことができます

_connection = [[NSURLConnection alloc] initWithRequest:request delegate:delegate startImmediately:NO];
[_connection scheduleInRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode];
于 2013-01-08T22:12:03.990 に答える
-1

このMPRequestを次のcontext performBlock:^{...}ように設定します。

__strong MPRequest = // allocate or set the MPRequest.
[context performBlock:^{...}

これで、performBlockが終了すると、MPRequestは解放されず、__strong句で指定した変数に設定されたままになります。

于 2013-01-08T20:36:30.570 に答える