我正在获取要从服务器下载的图像列表。过滤列表后,我将所有网络调用添加到信号数组中并合并它们。事情是网络调用开始了,但是与此同时,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块。

我看不出有任何明显的理由处理一次性用品。信号有误吗?您可以设置一个断点并查看调用取消的堆栈跟踪吗?

08-19 11:41