Асинхронный JSON-запрос и CoreData: UITableView не будет загружаться, пока не будет нажат - PullRequest
0 голосов
/ 25 октября 2018

Я пытаюсь загрузить данные Json из запроса URL-адреса, сохранить новые объекты в объектах CoreData и отобразить их в виде uitableview.загрузка и сохранение всех данных работают нормально.Моя проблема сводится к отображению его на UITableView.Когда он загружается, ничего не появляется, пока я не коснусь или прокрутить.это вызвало первую проблему, когда отношения не загружались вовремя и не появлялись пустыми в tableView.поэтому я решил подготовить данные в одном объекте перед отображением ячеек.это работает нормально, но осталась одна проблема - я должен нажать, прежде чем данные появятся.

@protocol LokalModelProtocol <NSObject,NSURLSessionDelegate,NSFetchedResultsControllerDelegate>
@required
-(void)itemsDownloaded;
-(void)mediaDownloaded;
@end

@interface LokalModel : NSObject

-(void)downloadItems;
@property (strong, nonatomic) NSMutableData* thedata;
@property (strong, nonatomic) NSString* urlString;
@property (strong, nonatomic) NSURL* theUrl;
@property (strong,nonatomic) id<LokalModelProtocol>delegate;
@property (strong,nonatomic) Media* media;
@property (strong,nonatomic) Post* post;
@property (strong,nonatomic) NSManagedObjectContext* managedObjectContext;
@property (strong,nonatomic) NSFetchedResultsController* fetchedResultsController;
 @property (strong,nonatomic) NSPersistentStoreCoordinator* persistentStoreCoordinator;
-(void)parseJson:(NSData*)data;
-(void)parseJsonMedia:(NSData*)data;
-(void)downloadMedia;
@end

@implementation LokalModel;
@synthesize thedata,urlString,theUrl,delegate,persistentStoreCoordinator,post,managedObjectContext,fetchedResultsController;


-(NSManagedObjectContext *) managedObjectContext
{
return [(AppDelegate*)[[UIApplication sharedApplication] delegate] managedObjectContext];
}

-(void)downloadItems{

  NSURLSession *currentSession= [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration]];
static NSString* urlString = @"https://balalatet.com/wp-json/wp/v2/posts";
theUrl=[NSURL URLWithString:urlString];



   NSURLSessionDataTask *task = [currentSession dataTaskWithURL:theUrl completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
    if (error){
        [NSException raise:@"error" format:@"%@",error.localizedDescription];
        NSLog(@"connection error1");
    }
    else{
        NSLog(@"connection success");
        [self parseJson:data];

    }
}];
[task resume];   
}
-(void)parseJsonMedia:(NSData *)data{
NSArray *jsonResults = [[NSArray alloc]init];
NSError *jsonerror;
@try {
    jsonResults =[NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingAllowFragments error:&jsonerror];
    if (jsonerror)
        [NSException raise:@"json error" format:@"%@",jsonerror.localizedDescription];
} @catch (NSException *exception) {
    NSLog(@"%@", exception.reason);
} @finally {
    NSLog(@"ran");
}
NSMutableDictionary *jsonElenent =[NSMutableDictionary dictionary];
dispatch_async(dispatch_get_main_queue(), ^{
    [self.managedObjectContext setMergePolicy:NSMergeByPropertyObjectTrumpMergePolicy];

});

for (NSMutableDictionary *d in jsonResults)
{
    jsonElenent=d;
    dispatch_async(dispatch_get_main_queue(), ^{

        self.media = [NSEntityDescription insertNewObjectForEntityForName:@"Media" inManagedObjectContext:[self managedObjectContext]];

        self.media.id= [NSString stringWithFormat: @"%@", jsonElenent[@"id"]];
        self.media.source_url= [NSString stringWithFormat: @"%@", jsonElenent[@"source_url"]];

        NSError *error = nil;
        if ([self.managedObjectContext hasChanges])
        {
            if (![self.managedObjectContext save:&error])
            {
                NSLog(@"Save Failed: %@", [error localizedDescription]);
            }
            else
            {
                NSLog(@"Save media Succeeded");
            }
        }             
    });
}

}
-(void)downloadMedia{


    NSURLSession *currentSession= [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration]];
static NSString* urlString = @"https://balalatet.com/wp-json/wp/v2/Media";
NSURL *theUrl2=[NSURL URLWithString:urlString];



   NSURLSessionDataTask *task3 = [currentSession dataTaskWithURL:theUrl2 completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
    if (error){
        [NSException raise:@"error" format:@"%@",error.localizedDescription];
        NSLog(@"connection error1");
    }
    else{
        NSLog(@"connection success");
        [self parseJsonMedia:data];

    }
}];
[task3 resume];


}

-(void)parseJson:(NSData*)data{

NSArray *jsonResults = [[NSArray alloc]init];
NSError *jsonerror;
@try {
    jsonResults =[NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingAllowFragments error:&jsonerror];
    if (jsonerror)
        [NSException raise:@"json error" format:@"%@",jsonerror.localizedDescription];
} @catch (NSException *exception) {
    NSLog(@"%@", exception.reason);
} @finally {
    NSLog(@"ran");
}

NSMutableArray *posts = [[NSMutableArray alloc] init];
NSMutableDictionary *jsonElenent =[NSMutableDictionary dictionary];

dispatch_async(dispatch_get_main_queue(), ^{
    [self.managedObjectContext setMergePolicy:NSMergeByPropertyObjectTrumpMergePolicy];
    [self downloadMedia];

});


for (NSMutableDictionary *d in jsonResults)
{
    jsonElenent=d;

     dispatch_async(dispatch_get_main_queue(), ^{

         self.post = [NSEntityDescription insertNewObjectForEntityForName:@"Post" inManagedObjectContext:[self managedObjectContext]];            
         self.post.id= [NSString stringWithFormat: @"%@", jsonElenent[@"id"]];
         self.post.date= [NSString stringWithFormat: @"%@", jsonElenent[@"date"]];
         self.post.date_gmt= [NSString stringWithFormat: @"%@", jsonElenent[@"date_gmt"]];
         self.post.guid= [NSString stringWithFormat: @"%@", jsonElenent[@"guid"]];
         self. post.slug= [NSString stringWithFormat: @"%@", jsonElenent[@"slug"]];
         self.post.status= [NSString stringWithFormat: @"%@", jsonElenent[@"status"]];
         self.post.sticky= [NSString stringWithFormat: @"%@", jsonElenent[@"sticky"]];
         self.post.ping_status= [NSString stringWithFormat: @"%@", jsonElenent[@"ping_status"]];
         self. post.type= [NSString stringWithFormat: @"%@", jsonElenent[@"type"]];
         self.post.comment_status=[NSString stringWithFormat: @"%@", jsonElenent[@"comment_status"]];
         self.post.tags=[NSString stringWithFormat: @"%@", jsonElenent[@"tags"]];
         self.post.title=[NSString stringWithFormat: @"%@", jsonElenent[@"title"]];
         self. post.template= [NSString stringWithFormat: @"%@", jsonElenent[@"template"]];
         self.post.link=[NSString stringWithFormat: @"%@", jsonElenent[@"link"]];
         self.post.meta=[NSString stringWithFormat: @"%@", jsonElenent[@"meta"]];
         self.post.modified=[NSString stringWithFormat: @"%@", jsonElenent[@"modified"]];
         self.post.modified_gmt=[NSString stringWithFormat: @"%@", jsonElenent[@"modified_gmt"]];
         self.post.featured_media=[NSString stringWithFormat: @"%@", jsonElenent[@"featured_media"]];
         self.post.format=[NSString stringWithFormat: @"%@", jsonElenent[@"format"]];
         self.post.links=[NSString stringWithFormat: @"%@", jsonElenent[@"links"]];
         self.post.author=[NSString stringWithFormat: @"%@", jsonElenent[@"author"]];
         self.post.content=[NSString stringWithFormat: @"%@", jsonElenent[@"content"]];
         self.post.categories= [NSString stringWithFormat: @"%@", jsonElenent[@"category"]];
         self.post.excerpt=[NSString stringWithFormat: @"%@", jsonElenent[@"excerpt"]];
         @try {
             NSFetchRequest *fetch = [[NSFetchRequest alloc] init];


             NSString *s =  jsonElenent[@"featured_media"];
             NSManagedObjectContext *cxt = [self managedObjectContext];

             NSEntityDescription *entity = [NSEntityDescription entityForName:@"Media" inManagedObjectContext:cxt];
             [fetch setEntity:entity];
             NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"id" ascending:YES];
             NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:sortDescriptor, nil];
             fetch.sortDescriptors = sortDescriptors;
             NSPredicate *predicate = [NSPredicate predicateWithFormat:@"id = %@", [NSString stringWithFormat: @"%@", s]];

             [fetch setPredicate:predicate];
             NSArray *temp  = [cxt executeFetchRequest:fetch error:nil];

             for (Media *m in temp)
             {
                // m.posts=self.post.medias;
                // self.post.medias=m.posts;
                 self.post.featured_media_link=m.source_url;
                 //m.posts=self.post;
                 // self.post.medias=m;
             }
         } @catch (NSException *exception) {
             NSLog(@"%@", exception.reason);

         } @finally {
             NSLog(@"done");
         }

        NSError *error = nil;
    if ([self.managedObjectContext hasChanges])
    {
        if (![self.managedObjectContext save:&error])
        {
            NSLog(@"Save Failed: %@", [error localizedDescription]);
        }
        else
        {
            NSLog(@"Save Succeeded");
        }
    }
        });
  }
 dispatch_async(dispatch_get_main_queue(), ^{
    [self.delegate itemsDownloaded];
   });
}
@end


    @interface MainTableViewController : UITableViewController<LokalModelProtocol,NSFetchedResultsControllerDelegate>

-(void)refreshTable;
@property (strong,nonatomic) UIRefreshControl* refCon;
@property (strong,nonatomic) NSMutableArray* arr;
@property (strong,nonatomic) LokalModel *lokal;
@property (strong,nonatomic) Media* media;
@property (strong,nonatomic) Post* post;
@property (strong,nonatomic) NSManagedObjectContext* managedObjectContext;
@property (strong,nonatomic) NSFetchedResultsController* fetchedResultsController;
@property (strong,nonatomic) NSPersistentStoreCoordinator* persistentStoreCoordinator;
@property (strong,nonatomic) NSString* type;
@end

@implementation MainTableViewController
@synthesize arr,refCon, lokal,managedObjectContext,fetchedResultsController,persistentStoreCoordinator,media,type,post;

-(NSManagedObjectContext *) managedObjectContext
{
    return [(AppDelegate*)[[UIApplication sharedApplication] delegate] managedObjectContext];
}

-(void)refreshTable{
   dispatch_async(dispatch_get_main_queue(), ^{

    [self.refCon endRefreshing];
       [self.tableView reloadData];
});
}

- (void)viewDidLoad {
    [super viewDidLoad];

    refCon = [[UIRefreshControl alloc]init];
    [self.tableView addSubview:refCon];
    [refCon addTarget:self action:@selector(refreshTable) forControlEvents:UIControlEventValueChanged];

    arr = [[NSMutableArray alloc]init];
    lokal = [[LokalModel alloc]init];
    lokal.delegate=self;
    [lokal downloadItems];


    NSLog(@"reached viewdidload");

}
-(void)viewWillAppear:(BOOL)animated{
    [super viewWillAppear:animated];
    [self refreshTable];
}

#pragma mark - Table view data source

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
//#warning Incomplete implementation, return the number of sections
    return 1;
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {

    id<NSFetchedResultsSectionInfo> sectionInfo = [[self.fetchedResultsController sections] objectAtIndex:section];
    NSLog(@"%lu", (unsigned long)[sectionInfo numberOfObjects]);
    return [sectionInfo numberOfObjects];

}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
    return 333.3f;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {


    ParallaxTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"mainCell" forIndexPath:indexPath];


    self.post = [self.fetchedResultsController objectAtIndexPath:indexPath];

     cell.titleLabel.text = [NSString stringWithFormat: @"%@", self.post.id];
    [cell.parallaxImage sd_setImageWithURL:[NSURL URLWithString:post.featured_media_link]
                 placeholderImage:[UIImage imageNamed:@"placeholder.png"]];

    return cell;
}

-(void)mediaDownloaded {

    NSLog(@"method called downloaded");

    [self refreshTable];

}

-(void)itemsDownloaded {

    NSError *error = nil;
    if (![[self fetchedResultsController] performFetch:&error])
    {
        NSLog(@"error: %@", error);
        abort();
    }
    [self refreshTable];

}

#pragma mark - Fetched Results Controller Section
-(NSFetchedResultsController*)fetchedResultsController

{
    if (fetchedResultsController != nil)
    {
        return fetchedResultsController;
    }
    NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];

    NSManagedObjectContext *context = [self managedObjectContext];

    NSEntityDescription *entity = [NSEntityDescription entityForName:@"Post" inManagedObjectContext:context];
    [fetchRequest setEntity:entity];
    NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"id" ascending:YES];
    NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:sortDescriptor, nil];
    fetchRequest.sortDescriptors = sortDescriptors;
    fetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:context sectionNameKeyPath:nil cacheName:nil];
    fetchedResultsController.delegate = self;
    return fetchedResultsController;
}


#pragma mark - Fetched Results Controller Delegates

- (void) controllerWillChangeContent:(NSFetchedResultsController *)controller
{
    [self.tableView beginUpdates];
}

-(void) controllerDidChangeContent:(NSFetchedResultsController *)controller
{
    [self.tableView endUpdates];
}

- (void)controller:(NSFetchedResultsController *)controller didChangeObject:(id)anObject atIndexPath:(NSIndexPath *)indexPath forChangeType:(NSFetchedResultsChangeType)type newIndexPath:(NSIndexPath *)newIndexPath
{
    UITableView *tableView = self.tableView;

    switch (type)
    {
        case NSFetchedResultsChangeInsert:
            [tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath] withRowAnimation:UITableViewRowAnimationFade];
            break;
        case NSFetchedResultsChangeDelete:
            [tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
            break;
        case NSFetchedResultsChangeUpdate:
        {
            Post *post = [self.fetchedResultsController objectAtIndexPath:indexPath];
            UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
            cell.textLabel.text = post.title;
        }
            break;
        case NSFetchedResultsChangeMove:
            [tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
            [tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath] withRowAnimation:UITableViewRowAnimationFade];
            break;

    }
}

- (void) controller:(NSFetchedResultsController *)controller didChangeSection:(id<NSFetchedResultsSectionInfo>)sectionInfo atIndex:(NSUInteger)sectionIndex forChangeType:(NSFetchedResultsChangeType)type
{
    switch (type)
    {
        case NSFetchedResultsChangeInsert:
            [self.tableView insertSections:[NSIndexSet indexSetWithIndex:sectionIndex] withRowAnimation:UITableViewRowAnimationBottom];
            break;
        case NSFetchedResultsChangeDelete:
            [self.tableView deleteSections:[NSIndexSet indexSetWithIndex:sectionIndex] withRowAnimation:UITableViewRowAnimationBottom];
            break;
        case NSFetchedResultsChangeMove:

            break;
        case NSFetchedResultsChangeUpdate:

            break;
    }
}

@end

Я должен описать свою модель данных, в основном я получаю данные из двух URL-адресов: один для постов и один дляМедиа, которые являются моими двумя объектами в моей модели CoreData.у них обоих есть уникальный идентификатор.сообщение имеет свойство featured_media, которое возвращает идентификатор связанного с ним носителя (я установил отношение «многие ко многим», но оно работает неправильно).так как я создаю объект post для каждого сообщения в массиве, я извлекаю связанный с ним носитель и сохраняю его URL-адрес в свойстве media_link в сущности Post.поэтому к этому времени методу cellForRowAtIndexPath требуется только один объект.но, опять же, он не будет показывать данные, пока я не буду с ним взаимодействовать.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...