2

UPDATTE:

I did forget to mention that the CollectionView is in the right hand side of a Split View Controller, and on the left side, I have tableView. When a row is selected, I pass a new FEED ADDRESS and have it run refreshFeed method on the right hand side.

I have a collection view which parses data from an XML. When a certain button is pressed, I want it to clear out the CollectionView, and load in data from a different XML, both of which are located online. I use ASIHTTPRequest and GDATAXML classes to help me pull this off. Here is my code. I can verify through logs that the NSMutableArray is cleared, and successfully populated with the different XML, but reloadData never happens, as cellForItem doesn't get called a 2nd time. Where have I messed up?

@interface RightViewController ()
@property (nonatomic, strong) IBOutlet UICollectionView *collectionView;

@end

@implementation RightViewController

@synthesize allEntries = _allEntries;
@synthesize feeds = _feeds;
@synthesize queue = _queue;
@synthesize webViewController = _webViewController;
@synthesize activity;
@synthesize webViewController2 = _webViewController2;



@synthesize nameit2;
@synthesize nowplaying;
@synthesize entryofmp3 = _entryofmp3;
@synthesize nameit;
@synthesize progress;
@synthesize lastSelection;
@synthesize backgroundTaskIdentifier, theurl;
@synthesize thetable, thepath, downloadlabel, receivedData, progressbutton;


-(NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView {
    return 1;
}
-(NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
    return [_allEntries count];
}
- (void)loadFirstTime {
       self.allEntries = [NSMutableArray array];

        self.queue = [[NSOperationQueue alloc] init];


    if (_feedAddress == nil) {
        _feedAddress = @"http://www.316apps.com/AIMAPPLETV/AIMSeries.xml";
    }
    self.feeds = [NSArray arrayWithObjects:_feedAddress,
                  nil];
    for (NSString *feed in _feeds) {
        NSLog(@"Running Fine");
        NSURL *url = [NSURL URLWithString:feed];
        ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url];
        [request setDelegate:self];
        [_queue addOperation:request];
    }
    NSLog(@"Still Good");
    //[self.collectionView reloadData];


}
-(void)changeFeed {
    [_allEntries removeAllObjects];
    _feedAddress = @"http://www.316apps.com/AIMAPPLETV/AIMCON.xml";
    [self loadFirstTime];
   // self.queue = nil;
    //_request.delegate = nil;
 //   _request.delegate = nil;

  //  [_collectionView reloadData];
}
-(void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath {
  // [self performSegueWithIdentifier:@"playMovies" sender:self];
     RSSEntry *entry = [_allEntries objectAtIndex:indexPath.row];
    NSString *wifiStreamAddress = entry.articleUrl;
    AVPlayer *player = [[AVPlayer alloc] initWithURL: [NSURL URLWithString: wifiStreamAddress] ];
    AVPlayerViewController *playerViewController = [[AVPlayerViewController alloc] init];
    playerViewController.player = player;

    // Keep pointers to player and controller
    self.player = player;
    self.playerViewController = playerViewController;



    [self presentViewController: playerViewController animated: true completion: ^{
        [self.player play];
    }];


}

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
    // Make sure your segue name in storyboard is the same as this line
    if ([[segue identifier] isEqualToString:@"playMovies"])
    {
        PlayMovies *userViewController = [segue destinationViewController];

        //if you need to pass data to the next controller do it here
    }
}
-(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {


    RSSEntry *entry = [_allEntries objectAtIndex:indexPath.row];

    static NSString *cellIdentifier = @"cvCell";

    CVCell *cell = (CVCell *)[collectionView dequeueReusableCellWithReuseIdentifier:cellIdentifier forIndexPath:indexPath];

        [cell.theimage setImageWithURL:[NSURL URLWithString:entry.articleImage] placeholderImage:[UIImage imageNamed:@"icon@2x.png"]];

    cell.theimage.adjustsImageWhenAncestorFocused = YES;
    cell.theimage.clipsToBounds = false;




    return cell;
}

- (void)viewDidLoad {
        [super viewDidLoad];

    self.allEntries = [NSMutableArray array];
    self.queue = [[NSOperationQueue alloc] init];
        [self loadFirstTime];

}
-(void) viewWillAppear:(BOOL)animated {

}

- (void)parseRss:(GDataXMLElement *)rootElement entries:(NSMutableArray *)entries {

    NSArray *channels = [rootElement elementsForName:@"channel"];
    for (GDataXMLElement *channel in channels) {

        NSString *blogTitle = [channel valueForChild:@"title"];

        NSArray *items = [channel elementsForName:@"item"];
        for (GDataXMLElement *item in items) {
            NSString *articleTitle = [item valueForChild:@"title"];
            NSString *articleUrl = [[[[item elementsForName: @"enclosure"] lastObject] attributeForName: @"url"] stringValue];
            NSString *articleDateString = [item valueForChild:@"pubDate"];
            NSString *picture = [[[[item elementsForName: @"itunes:image"] lastObject] attributeForName: @"href"] stringValue];
            NSDate *articleDate = [NSDate dateFromInternetDateTimeString:articleDateString formatHint:DateFormatHintRFC822];
            RSSEntry *entry = [[RSSEntry alloc] initWithBlogTitle:blogTitle
                                                      articleTitle:articleTitle
                                                        articleUrl:articleUrl
                                                       articleDate:articleDate
                                                      articleImage:picture];


            [entries addObject:entry];
            NSLog(@"%@", entries);
        }
    }
     [self.collectionView reloadData];
}

- (void)parseFeed:(GDataXMLElement *)rootElement entries:(NSMutableArray *)entries {

    if ([rootElement.name compare:@"rss"] == NSOrderedSame) {
        [self parseRss:rootElement entries:entries];
    } else if ([rootElement.name compare:@"feed"] == NSOrderedSame) {
       // [self parseAtom:rootElement entries:entries];
    } else {
        NSLog(@"Unsupported root element: %@", rootElement.name);
    }
}

- (void)requestFinished:(ASIHTTPRequest *)request {
    NSLog(@"Request Finished");
    [_queue addOperationWithBlock:^{

        NSError *error;
        GDataXMLDocument *doc = [[GDataXMLDocument alloc] initWithData:[request responseData]
                                                               options:0 error:&error];
        if (doc == nil) {
            NSLog(@"Failed to parse %@", request.url);
        } else {

            NSMutableArray *entries = [NSMutableArray array];
            [self parseFeed:doc.rootElement entries:entries];

            [[NSOperationQueue mainQueue] addOperationWithBlock:^{

                for (RSSEntry *entry in entries) {

                    int insertIdx = [_allEntries indexForInsertingObject:entry sortedUsingBlock:^(id a, id b) {
                        RSSEntry *entry1 = (RSSEntry *) a;
                        RSSEntry *entry2 = (RSSEntry *) b;
                        return [entry1.articleDate compare:entry2.articleDate];
                    }];
                                       [_allEntries insertObject:entry atIndex:insertIdx];


                }

            }];

        }
    }];

}

- (void)requestFailed:(ASIHTTPRequest *)request {
    NSError *error = [request error];
    NSLog(@"Error: %@", error);
    [self loadFirstTime];
}


- (void)didReceiveMemoryWarning
{
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

@end

SECOND UPDATE:

I'm slowly getting somewhere. Think it was due to me not having a Segue set up. I drug a segue from the Cell of the Left Side's TableView to the Collection View's View Controller and set up as ShowDetail, and named it. Then in LeftViewController:

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
    if (indexPath.row == 1) {
        [self performSegueWithIdentifier:@"doingIt" sender:self];

    }
}
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
    // Make sure your segue name in storyboard is the same as this line
    if ([[segue identifier] isEqualToString:@"doingIt"])
    {

        self.rightViewController = [[RightViewController alloc] init];
                [self.rightViewController refresheyc];

        //if you need to pass data to the next controller do it here
    }
}

In the RightViewController I have:

-(void)refresheyc {
    NSLog(@"This Sucks");
    [self.allEntries removeAllObjects];
    [self.collectionView reloadData];
    self.allEntries = nil;
    self.queue = nil;
    self.allEntries = [NSMutableArray array];

    self.queue = [[NSOperationQueue alloc] init];




    self.feeds = [NSArray arrayWithObjects:@"http://www.316apps.com/AIMAPPLETV/AIMCON.xml",
                  nil];
    for (NSString *feed in _feeds) {
        NSURL *url = [NSURL URLWithString:feed];
        NSLog(@"URL%@", url);
        ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url];
        [request setDelegate:self];
        [_queue addOperation:request];
    }

}

The Cells in CollectionView immediately disappear, but after several seconds, they all come back just the same, not changing the XML at all, but I get this:

2016-01-09 14:37:31.542 AIM-TV[7965:522091] This application is modifying the autolayout engine from a background thread, which can lead to engine corruption and weird crashes.  This will cause an exception in a future release.
 Stack:(
    0   CoreFoundation                      0x0000000109fa6ff5 __exceptionPreprocess + 165
    1   libobjc.A.dylib                     0x000000010d45cdeb objc_exception_throw + 48
    2   CoreFoundation                      0x0000000109fa6f2d +[NSException raise:format:] + 205
    3   Foundation                          0x000000010aa96341 _AssertAutolayoutOnMainThreadOnly + 79
    4   Foundation                          0x000000010a8f6d6e -[NSISEngine withBehaviors:performModifications:] + 31
    5   UIKit                               0x000000010c804eb8 -[UIView(AdditionalLayoutSupport) _withAutomaticEngineOptimizationDisabledIfEngineExists:] + 58
    6   UIKit                               0x000000010c804854 __57-[UIView(AdditionalLayoutSupport) _switchToLayoutEngine:]_block_invoke + 646
    7   UIKit                               0x000000010c804ec1 -[UIView(AdditionalLayoutSupport) _withAutomaticEngineOptimizationDisabledIfEngineExists:] + 67
    8   UIKit                               0x000000010c804589 -[UIView(AdditionalLayoutSupport) _switchToLayoutEngine:] + 242
    9   UIKit                               0x000000010c80405d -[UIView(AdditionalLayoutSupport) _initializeHostedLayoutEngine] + 649
    10  UIKit                               0x000000010c7f652a -[UIView(UIConstraintBasedLayout) _initializeLayoutEngine] + 152
    11  UIKit                               0x000000010c7f652a -[UIView(UIConstraintBasedLayout) _initializeLayoutEngine] + 152
    12  UIKit                               0x000000010c804e24 -[UIView(AdditionalLayoutSupport) _layoutEngineCreateIfNecessary] + 62
    13  UIKit                               0x000000010c7f732b -[UIView(UIConstraintBasedLayout) _tryToAddConstraint:roundingAdjustment:mutuallyExclusiveConstraints:] + 126
    14  UIKit                               0x000000010c7f75ef -[UIView(UIConstraintBasedLayout) _addConstraint:] + 274
    15  UIKit                               0x000000010c7fd247 -[UIView(UIConstraintBasedLayout) _updateContentSizeConstraints] + 779
    16  UIKit                               0x000000010c806270 -[UIView(AdditionalLayoutSupport) updateConstraints] + 224
    17  UIKit                               0x000000010c80559b -[UIView(AdditionalLayoutSupport) _internalUpdateConstraintsIfNeededAccumulatingViewsNeedingSecondPassAndViewsNeedingBaselineUpdate:forSecondPass:] + 550
    18  UIKit                               0x000000010c805866 -[UIView(AdditionalLayoutSupport) _updateConstraintsIfNeededAccumulatingViewsNeedingSecondPassAndViewsNeedingBaselineUpdate:forSecondPass:] + 198
    19  UIKit                               0x000000010c8054aa -[UIView(AdditionalLayoutSupport) _internalUpdateConstraintsIfNeededAccumulatingViewsNeedingSecondPassAndViewsNeedingBaselineUpdate:forSecondPass:] + 309
    20  UIKit                               0x000000010c805866 -[UIView(AdditionalLayoutSupport) _updateConstraintsIfNeededAccumulatingViewsNeedingSecondPassAndViewsNeedingBaselineUpdate:forSecondPass:] + 198
    21  UIKit                               0x000000010c8054aa -[UIView(AdditionalLayoutSupport) _internalUpdateConstraintsIfNeededAccumulatingViewsNeedingSecondPassAndViewsNeedingBaselineUpdate:forSecondPass:] + 309
    22  UIKit                               0x000000010c804ec1 -[UIView(AdditionalLayoutSupport) _withAutomaticEngineOptimizationDisabledIfEngineExists:] + 67
    23  UIKit                               0x000000010c80583a -[UIView(AdditionalLayoutSupport) _updateConstraintsIfNeededAccumulatingViewsNeedingSecondPassAndViewsNeedingBaselineUpdate:forSecondPass:] + 154
    24  UIKit                               0x000000010c805e9e __60-[UIView(AdditionalLayoutSupport) updateConstraintsIfNeeded]_block_invoke + 98
    25  UIKit
user717452
  • 33
  • 14
  • 73
  • 149
  • did you specify `collectionView` delegate the `RightViewController` ? – Ratul Sharker Jan 09 '16 at 19:00
  • Yes, in my Storyboard I have the outlet of collectionView that I declared at the top dragged over to the CollectionView, and then under Referencing Outlets drug over for dataSource as well as delegate. It loads the collectionView up just fine the first time around, but it is afterwards when trying to get it to reload that nothing happens. @RatulSharker – user717452 Jan 09 '16 at 19:07
  • @user717452: Where is your `refreshfree` method ? – Midhun MP Jan 09 '16 at 19:08
  • @MidhunMP My mistake. That's what I had it named before, and I had renamed the method in my post, but not where I was calling it. I have updated my OP to reflect this. refresh free and loadFirstTime were the same. – user717452 Jan 09 '16 at 19:17
  • I have been trying this for a couple days now to no avail. I did forget to mention that the CollectionView is in the right hand side of a Split View Controller, and on the left side, I have tableView. When a row is selected, I pass a new FEED ADDRESS and have it run refreshFeed method on the right hand side. – user717452 Jan 09 '16 at 20:06
  • @RatulSharker Check out the SECOND UPDATE I made. – user717452 Jan 09 '16 at 20:41

4 Answers4

4

Issue is really weird but it somehow works for me like, i added the update constraint code in the animation block,

UIView.animate(withDuration: 0.5, animations: {() -> Void in

    //update constraints here

    self.view.layoutIfNeeded() 
    self.collectionView.layoutIfNeeded()

})

self.collectionView.reloadData()
Shrikant K
  • 1,988
  • 2
  • 23
  • 34
2

You can't update UI elements in a background thread. [self.collectionView reloadData] is called from parseRss which is itself called form parseFeed which is called by an operation on _queue. if _queue doesn't happen to be processed by the main thread, you will get unpredictable results in the collectionView and more likely crashes.

You should dispatch your call to [self.collectionView reloadData] to the main thread.

dispatch_async(dispatch_get_main_queue(), { self.collectionView.reloadData() })

(this is the Swift syntax, i'm not familiar with Obj-C, sorry)

Alain T.
  • 40,517
  • 4
  • 31
  • 51
  • I tried that but it didnt work for me. I'm using Swift 3. – nyxee Jul 21 '17 at 03:29
  • In swift i got similar issue weird but its some how working – Abhishek Thapliyal Aug 12 '17 at 03:49
  • I posted my problem here: [CollectionViewController.reloadData() with data from a Parse Server](https://stackoverflow.com/questions/45232915/collectionviewcontroller-reloaddata-with-data-from-a-parse-server) – nyxee Aug 13 '17 at 10:43
0

As stated in Alain's answer, it is because UI changes need to be handled by the main thread. I see the question was posted using Objective C and answered in Swift so thought i'd post the Objective C version in case anyone needs it.

dispatch_async(dispatch_get_main_queue(), ^ {
    [self.collectionView reloadData];
});
Niall Kiddle
  • 1,477
  • 1
  • 16
  • 35
0

Besides what @Alain T. mentions wrt dspatching the call to reloadData(), make sure your item height is set appropriately. When itemHeight is zero or some very large value, you might see the collectionView(numberOfItemsInSection) and numberOfSections() called as expected but not your collectionView( cellForItemAt).

So make sure you have item height set with a call to:

collectionView(collectionView, layout, sizeForItemAt)
Yohst
  • 1,671
  • 18
  • 37