私は2つのクラスを持っていMPRequest
ますMPModel
. このMPModel
クラスには、コア データ ストアから何かを検索するメソッドがあり、見つからない場合はMPRequest
、標準の HTTP 要求を介してそれを取得するための を作成します (のメソッドMPModel
は静的であり、インスタンス メソッドではありません)。
私が望むのは、現在の HTTP リクエストの進行状況を取得できるようにすることです。これを行う方法は知っていますが、View Controllerに通知する方法に少し行き詰まっています。プロトコルを作成し、MPRequest
クラスでデリゲート プロパティを定義しMPModel
、このデリゲートを受け入れるようにメソッドを変更し、作成時に に渡してみMPRequest
ました。
これは問題ありませんが、ARC はリクエストの実行中にこのデリゲートを解放しているため、私が望むことを行いません。参照サイクルがスローされる場合に備えて、デリゲート オブジェクトを強い参照にしないようにしていますが、これを行う他の方法がわかりません。
リクエストを開始するには、実行しているView Controllerから
[MPModel findAllWithBlock:^(NSFetchedResultsController *controller, NSError *error) {
....
} sortedBy:@"name" ascending:YES delegate:self]
findAllWithBlock メソッド内には、
MPRequest *objRequest = [MPRequest requestWithURL:url];
objRequest.delegate = delegate;
[objRequest setRequestMethod:@"GET"];
[MPUser signRequest:objRequest];
[objRequest submit:^(MPResponse *resp, NSError *err) {
...
}
クラスでMPRequest
は、次のプロパティが定義されています。
@property (nonatomic, weak) NSObject<MPRequestDelegate> *delegate;
アイデアや提案はありますか?
リクエストに応じて、呼び出し方法に関するコードを次に示します。
ビューコントローラーで:
[MPPlace findAllWithBlock:^(NSFetchedResultsController *controller, NSError *error) {
_placesController = controller;
[_listView reloadData];
[self addAnnotationsToMap];
[_loadingView stopAnimating];
if (_placesController.fetchedObjects.count > 0) {
// We've got our places, but if they're local copies
// only, new ones may have been added so just update
// our copy
MPSyncEngine *engine = [[MPSyncEngine alloc] initWithClass:[MPPlace class]];
engine.delegate = self;
[engine isReadyToSync:YES];
[[MPSyncManager sharedSyncManager] registerSyncEngine:engine];
[[MPSyncManager sharedSyncManager] sync];
}
} sortedBy:@"name" ascending:YES delegate:self];
ここで、明らかな理由で self が解放されることは決してないので、これがどのように問題なのかわかりません。
上記MPPlace
は のサブクラスですMPModel
が、 の実装findAllWithBlock:sortedBy:ascending:delegate:
は完全にMPModel
内のメソッドはMPModel
次のようになります
NSManagedObjectContext *context = [[MPCoreDataManager sharedInstance] managedObjectContext];
[context performBlockAndWait:^{
__block NSError *error;
NSFetchRequest *request = [[NSFetchRequest alloc] initWithEntityName:NSStringFromClass([self class])];
[request setSortDescriptors:@[[[NSSortDescriptor alloc] initWithKey:key ascending:asc]]];
NSFetchedResultsController *controller = [[NSFetchedResultsController alloc] initWithFetchRequest:request
managedObjectContext:context
sectionNameKeyPath:nil
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.delegate = delegate;
[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
デリゲートは、作成中のオブジェクトに渡されるだけです。私の最初の懸念は、作成中の MPRequest オブジェクトが ARC によってリリースされていることでした (おそらくそうであると思います) が、変更しても何も修正されませんでした。メソッドが静的であるため、iVar にすることはできません。
リクエストの送信メソッドは次のようになります。
_completionBlock = block;
_responseData = [[NSMutableData alloc] init];
[self prepareRequest];
[self prepareRequestHeaders];
_connection = [[NSURLConnection alloc] initWithRequest:_urlRequest
delegate:self];
アプリがデータのダウンロードを開始すると、次のように呼び出します。
[_responseData appendData:data];
[_delegate requestDidReceive:(float)data.length ofTotal:_contentLength];
_contentLength はlong
、応答の予想されるサイズを格納するだけです。