Welcome to the Treehouse Community

Want to collaborate on code errors? Have bugs you need feedback on? Looking for an extra set of eyes on your latest project? Get support with fellow developers, designers, and programmers of all backgrounds and skill levels here with the Treehouse Community! While you're at it, check out some resources Treehouse students have shared here.

Looking to learn something new?

Treehouse offers a seven day free trial for new students. Get access to thousands of hours of content and join thousands of Treehouse students and alumni in the community today.

Start your free trial

iOS

Lukáš Orgován
Lukáš Orgován
1,924 Points

UICollectionView not showing

I made an asynchronous call to xml data on internet, they are fetched, i use parser to parse them (and i use nslog to be sure its ok). Everything seems to be alright but data will not show, i have blank "view".

//
//  ViewController.m
//  Events
//
//  Created by Lukas Orgovan on 11/5/12.
//  Copyright (c) 2012 Lukas Orgovan. All rights reserved.
//

#import "ViewController.h"
#import "DetailViewController.h"
#import "CollectionViewCell.h"

@interface ViewController ()



@end

@implementation ViewController


@synthesize xmlParser = _xmlParser;
@synthesize currentEvent = _currentEvent;
@synthesize currentString = _currentString;
@synthesize storeCharacters = _storeCharacters;
@synthesize eventsArray = _eventsArray;
@synthesize recievedData = _recievedData;
- (void)viewDidLoad
{
    [super viewDidLoad];
    [_spinner startAnimating];

    // Create the request.
    NSURLRequest *theRequest=[NSURLRequest requestWithURL:       [NSURL URLWithString:@"http://www.90bpm.sk/feeds/iphone.xml"]
                                              cachePolicy:NSURLRequestUseProtocolCachePolicy
                                      timeoutInterval:60.0];
    // create the connection with the request
    // and start loading the data
    NSURLConnection *theConnection=[[NSURLConnection alloc]  initWithRequest:theRequest delegate:self];
    if (theConnection) {
        // Create the NSMutableData to hold the received data.
        // receivedData is an instance variable declared elsewhere.
        self.recievedData = [NSMutableData data];
    } else {
    // Inform the user that the connection failed.
   }


}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
// do something with the data
// receivedData is declared as a method instance elsewhere
NSLog(@"Succeeded! Received %d bytes of data",[self.recievedData length]);
[_spinner stopAnimating];
// release the connection, and the data object
self.xmlParser = [[NSXMLParser alloc] initWithData:self.recievedData];
self.xmlParser.delegate = self;
self.eventsArray = [NSMutableArray array];
self.currentString = [NSMutableString string];
[self.xmlParser parse];

}
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
// This method is called when the server has determined that it
// has enough information to create the NSURLResponse.

// It can be called multiple times, for example in the case of a
// redirect, so each time we reset the data.

// receivedData is an instance variable declared elsewhere.
[self.recievedData setLength:0];
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
// Append the new data to receivedData.
// receivedData is an instance variable declared elsewhere.
[self.recievedData appendData:data];
}
- (void)connection:(NSURLConnection *)connection
didFailWithError:(NSError *)error
{
// release the connection, and the data object

// receivedData is declared as a method instance elsewhere


// inform the user
NSLog(@"Connection failed! Error - %@ %@",
      [error localizedDescription],
      [[error userInfo] objectForKey:NSURLErrorFailingURLStringErrorKey]);
}


#pragma mark -
#pragma mark SEGUE !!!

- (void) prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ( [[segue identifier] isEqualToString:@"showDetails"] ) {

    NSIndexPath *indexPath = [[self.collectionView indexPathsForSelectedItems] lastObject];
    NSLog(@"%d", indexPath.row);

    DetailViewController *dvc = (DetailViewController *) [segue destinationViewController];
    //dvc.detail = [self.eventsArray objectAtIndex:(indexPath.row)];
    dvc.detail = [self.eventsArray objectAtIndex:indexPath.row];


}
}



#pragma mark -
#pragma mark UICollectionViewDataSource!!!

- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView {
return 1;
}
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
return [self.eventsArray count];
}
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
    CollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"Cell" forIndexPath:indexPath];
    Event *event = [self.eventsArray objectAtIndex:(indexPath.section*2 + indexPath.row)];
    cell.label.text = event.title;
    cell.imageView.image = [UIImage imageWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:event.image]]];
    return cell;
}

#pragma mark - 
#pragma mark Parser Delegate

static NSString *kName_Event = @"item";
static NSString *kName_Title = @"title";
static NSString *kName_Body = @"description";
static NSString *kname_Image = @"image";
static NSString *kName_Link = @"link";
- (void) parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict {

if ([elementName isEqualToString:kName_Event]) {
    self.currentEvent = [[Event alloc] init];
    self.storeCharacters = NO;
}
else if ([elementName isEqualToString:kName_Title] || [elementName isEqualToString:kname_Image] || [elementName isEqualToString:kName_Body] || [elementName isEqualToString:kName_Link]) {
    [self.currentString setString:@""];
    self.storeCharacters = YES;
}
}

- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string {
if (self.storeCharacters)
    [self.currentString appendString:string];
}

- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName {

if ([elementName isEqualToString:kName_Title]) {
    self.currentEvent.title = _currentString;


}
else if ([elementName isEqualToString:kname_Image]) {
    self.currentEvent.image = _currentString;

}
else if ([elementName isEqualToString:kName_Link]) {
   self.currentEvent.link = _currentString;

}
else if ([elementName isEqualToString:kName_Body]) {
   self.currentEvent.body = _currentString;

}
if ([elementName isEqualToString:kName_Event]) {
    [self finishedCurrentEvent: _currentEvent];
}
self.storeCharacters = NO;
}
- (void) finishedCurrentEvent:(Event *)e {
    [self.eventsArray addObject:e];
    self.currentEvent = nil;
}

- (void)parser:(NSXMLParser *)parser parseErrorOccurred:(NSError *)parseError {
    //postarj sa o errory pri parsovani
}

- (void)parserDidEndDocument:(NSXMLParser *)parser {
    NSLog(@"pocet vyparsovanych itemov / elementov: %d", _eventsArray.count);
    Event *eevveenntt = self.eventsArray[0];
    NSLog(@"konkretne: %@", eevveenntt.title);
}


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

@end

2 Answers

Amit Bijlani
STAFF
Amit Bijlani
Treehouse Guest Teacher

Your collection view loads before the parsing finishes and so it doesn't display anything because your eventsArray is empty. Once your parsing ends you need send a reload message to your collectionView so that it can retrieve data from the eventsArray which now has the parsed data. So essentially this is what your parserDidEndDocument should look like:

- (void)parserDidEndDocument:(NSXMLParser *)parser {
    [self.collectionView reloadData];
}
Lukáš Orgován
Lukáš Orgován
1,924 Points

You are the best. No really, you are something like a little god of iOS for me :) Thank you!