我正在获取要从服务器下载的图像列表。过滤列表后,我将所有网络调用添加到信号数组中并合并它们。事情是网络调用开始了,但是与此同时,racdisposable被销毁了,在destroy方法中,我对下载任务调用了cancel。调用取消将停止请求,并且不会拉出图像。关于如何执行此操作的任何建议?我对IOS和ReactiveCocoa很陌生
该方法启动请求
- (void)fetchTagsFromServer{
[self CreateIfNotExistsTagsFolder];
//define URL object
NSString *urlString = [NSString stringWithFormat:@"http://studiotest.cloudapp.net:5508/api/sideviewapi/gettags"];
NSURL *url = [NSURL URLWithString:urlString];
//fetch tag list from server. After the json is here, start filtering and pulling the images
//from the server
[[self fetchJSONFromURL:url] subscribeNext:^(id x){
NSDictionary* json = (NSDictionary*)x;
//filter and pull images
[[self handleTagsFromJson:json] subscribeNext:^(id x) {
initTagsDone = false;
} error:^(NSError *error) {
NSLog([error description]);
}] ;
}];
}
这是从服务器提取json的通用方法
- (RACSignal *)fetchJSONFromURL:(NSURL *)url {
NSLog(@"Fetching: %@",url.absoluteString);
// RAC signal
return [[RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
//Create session task
NSURLSessionDataTask *dataTask = [self.session dataTaskWithURL:url completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
if (! error) {
NSError *jsonError = nil;
id json = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:&jsonError];
if (! jsonError) {
//if json returned with success sent to subscriber
[subscriber sendNext:json];
}
else {
// send json error to subscriber
[subscriber sendError:jsonError];
}
}
else {
// send general error
[subscriber sendError:error];
}
// send request completed
[subscriber sendCompleted];
}];
//Starts the the network request once someone subscribes to the signal.
[dataTask resume];
// Creates and returns an RACDisposable object which handles any cleanup when the signal when it is destroyed.
return [RACDisposable disposableWithBlock:^{
[dataTask cancel];
}];
}] doError:^(NSError *error) {
// log error
NSLog(@"%@",error);
}] ;
}
在这里,我结合了所有信号
(RACSignal *) handleTagsFromJson:(NSDictionary*) json {
//hold tags dto's
NSMutableArray* tags = [[NSMutableArray alloc] init];
NSMutableArray* signals = [[NSMutableArray alloc]init];
//create dto object from json
for (NSDictionary * item in json) {
TagsDTO* dto = [[TagsDTO alloc]init];
dto.Id = [[item valueForKey:@"Id"] intValue];
dto.BigIcon = [item valueForKey:@"BigIcon"];
dto.SmallIcon = [item valueForKey:@"SmallIcon"];
dto.SmallIconRaster = [item valueForKey:@"SmallIconRaster"];
dto.Date = [TagsDTO dateWithJSONString:[item valueForKey:@"Modified"]];
dto.Type = [[item valueForKey:@"Type"] intValue];
[tags addObject:dto];
}
//foreach dto do stuff with db
for (TagsDTO* tagDTO in tags){
//get DB tag by external ID
TAG* dbTag = [self getTagsByExternalID:tagDTO.Id];
//create holder strings for image names
NSString* pickerTag;
NSString* overlay;
NSString* raster;
//if db tag is null create null,else set values from server
if(dbTag == NULL){
TAG* tag = [NSEntityDescription insertNewObjectForEntityForName:@"TAG" inManagedObjectContext:self.managedObjectContext];
tag.externalId = [NSNumber numberWithInt:tagDTO.Id];
tag.pickerITag = pickerTag = tagDTO.BigIcon;
tag.overlayTag = overlay = tagDTO.SmallIcon;
tag.rasterTag = raster = tagDTO.SmallIconRaster;
tag.modified = tagDTO.Date;
tag.type = [NSNumber numberWithInt:tagDTO.Type];
}else{
dbTag.externalId = [NSNumber numberWithInt:tagDTO.Id];
dbTag.pickerITag = pickerTag = tagDTO.BigIcon;
dbTag.overlayTag = overlay = tagDTO.SmallIcon;
dbTag.rasterTag = raster = tagDTO.SmallIconRaster;
dbTag.modified = tagDTO.Date;
dbTag.type = [NSNumber numberWithInt:tagDTO.Type];
}
NSError *error ;
if (![self.managedObjectContext save:&error]) {
NSLog(@"Whoops, couldn't save: %@", [error localizedDescription]);
}
//start downloading images
//because there are 3 different types for each images, download from coressponding serveer folder
//get picker picture
[signals addObject: [self fetchTagImage:pickerTag area:@"picker"]];
//get overlay picture
[signals addObject: [self fetchTagImage:pickerTag area:@"overlay"]];
//get raster picture
[signals addObject:[self fetchTagImage:pickerTag area:@"raster"]];
}
return [RACSignal combineLatest:signals];
}
这是从服务器提取图像的信号
(RACSignal *) fetchTagImage:(NSString*)tag area: (NSString*) area {
//create Url object, area is the folder on the server
NSString *urlStringIcon = [NSString stringWithFormat:@"http://studiotest.cloudapp.net:5508/content/uploads/%@/%@",area,tag];
NSURL *urlIcon = [NSURL URLWithString:urlStringIcon];
NSLog(@"Fetching: %@",urlIcon.absoluteString);
// RAC signal
return [[RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
//Create session task
NSLog(@"internal image fetch: %@",urlIcon.absoluteString);
NSURLSessionDownloadTask* dataTask = [self.session downloadTaskWithURL:urlIcon completionHandler:^(NSURL*location, NSURLResponse *response, NSError *error) {
if(error == nil || error.code == NSURLErrorCancelled)
{
NSLog(@"Temporary file =%@",location);
NSError *err = nil;
//create file mananger
NSFileManager *fileManager = [NSFileManager defaultManager];
//get app document folder path
NSString *docsDir = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
//create actual store path
NSString *dataPath = [docsDir stringByAppendingPathComponent:@"/tags"];
//compile filename
NSString* filename = [NSString stringWithFormat:@"%@-%@",area,[response suggestedFilename]];
//create URL to move temporary item to
NSURL *docsDirURL = [NSURL fileURLWithPath:[dataPath stringByAppendingPathComponent:filename]];
if ([fileManager moveItemAtURL:location
toURL:docsDirURL
error: &err])
{
[subscriber sendNext:filename];
NSLog(@"File is saved to =%@",docsDir);
}
else
{
[subscriber sendError:err];
NSLog(@"failed to move: %@",[err userInfo]);
}
}else {
// send general error
[subscriber sendError:error];
}
// send request completed
[subscriber sendCompleted];
}];
//Starts the the network request once someone subscribes to the signal.
[dataTask resume];
// Creates and returns an RACDisposable object which handles any cleanup when the signal when it is destroyed.
return [RACDisposable disposableWithBlock:^{
[dataTask cancel];
}];
}] doError:^(NSError *error) {
// log error
NSLog(@"%@",error);
}];
}
最佳答案
让我们先检查几件事:
一次性垃圾被破坏
可以释放RACDisposable
。请注意,这不会调用一次性对象的dispose
块。
我看不出有任何明显的理由处理一次性用品。信号有误吗?您可以设置一个断点并查看调用取消的堆栈跟踪吗?