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
Jack Ryder
7,286 Pointsdownloading images from Parse and displaying in a collectionView cell
I'm trying to download images from Parse and then display them in a collectionViewCell. I get as far as successfully querying parse for the images i want to display but I'm having trouble displaying them, any ideas?
#import "JRViewController.h"
#import "PhotoCell.h"
#import <Parse/Parse.h>
#import "FriendsViewController.h"
@interface JRViewController ()
@end
@implementation JRViewController
- (void)viewDidLoad
{
[super viewDidLoad];
PFUser *currentUser = [PFUser currentUser];
if (currentUser) {
NSLog(@"Current User: %@", currentUser.username);
}
else {
[self performSegueWithIdentifier:@"Segue1" sender:self];
}
[self refresh];
self.edgesForExtendedLayout = UIRectEdgeNone;
UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc]init];
[layout setItemSize:CGSizeMake(306.0, 306.0)];
[layout setMinimumInteritemSpacing:150.0];
[layout setMinimumLineSpacing:130.0];
UICollectionView *collectionView = [[UICollectionView alloc]initWithFrame:self.view.frame collectionViewLayout:layout];
[collectionView setDataSource:self];
[collectionView setDelegate:self];
[collectionView registerClass:[PhotoCell class] forCellWithReuseIdentifier:@"photo"];
[self.view addSubview:collectionView];
[collectionView setBackgroundColor:[UIColor whiteColor]];
}
-(NSInteger) collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
return[imageFilesArray count];
}
- (UICollectionViewCell *) collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
PhotoCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"photo" forIndexPath:indexPath];
cell.backgroundColor = [UIColor whiteColor];
PFObject *imageObject = [imageFilesArray objectAtIndex:indexPath.row];
PFFile *imageFile = [imageObject objectForKey:@"file"];
[imageFile getDataInBackgroundWithBlock:^(NSData *data, NSError *error) {
if (!error){
NSLog(@"is there any data? %@", data);
cell.imageView.image = [UIImage imageWithData:data];
[self.collectionView reloadData];
}
else {
NSLog(@"no data!");
}
}];
return cell;
}
-(void)refresh{
PFUser *currentUser = [PFUser currentUser];
if (currentUser){
self.friendsRelation = [[PFUser currentUser] objectForKey:@"friendsRelation"];
PFQuery *query = [self.friendsRelation query];
[query orderByAscending:@"username"];
[query findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
if (error) {
NSLog(@"error: %@ %@", error, [error userInfo]);
}
else {
self.friends = objects;
NSLog(@"holla %@", self.friends);
PFQuery *queryFriends = [PFQuery queryWithClassName:@"Posts"];
[queryFriends whereKey:@"senderName" matchesKey:@"username" inQuery:query];
[queryFriends findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
if (error) {
NSLog(@"error: %@ %@", error, [error userInfo]);
}
else {
imageFilesArray = [[NSArray alloc]initWithArray:objects];
NSLog(@"images array objects %@", objects);
[self.collectionView reloadData];
NSLog(@"hello %@", imageFilesArray);
}
}];
}
}];
}
else {
NSLog(@"woops no user");
}
}
- (IBAction)logout:(id)sender {
[PFUser logOut];
[self performSegueWithIdentifier:@"Segue1" sender:self];
}
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([segue.identifier isEqualToString:@"Segue1"]) {
[segue.destinationViewController setHidesBottomBarWhenPushed:YES];
}
}
@end
Thanks!
18 Answers
Stone Preston
42,016 Pointswhere did you define this imageFiles array ivar seen here [imageFilesArray count]? i dont see it declared anywhere?
Stone Preston
42,016 PointsWHen you log the photo objects in your imageFiles array are you seeing your objects there in the console? Also im not sure this line
[collectionView setDataSource:self];
is necessary, try removing that and see what happens.
Jack Ryder
7,286 PointsYes i'm seeing the photo objects in the console but when i try log the data in 'collectionView numberOfItemsInSection' I can't see that. I've removed that and there doesn't seem to be a difference
Stone Preston
42,016 Pointsok. now it appears you arent loggin your imageFiles array, you are logging the objects array. so fix that so it logs the imagesArrray. something might be going on with that array.
imageFilesArray = [[NSArray alloc]initWithArray:objects];
NSLog(@"images array objects %@", imagesFilesArray);
[self.collectionView reloadData];
do you still see your objects logged after making that change?
Jack Ryder
7,286 Pointsah yeah when i make that change the imagesArray is empty
else {
imageFilesArray = [[NSArray alloc]initWithArray:objects];
NSLog(@"images array objects %@", imagesArray);
[self.collectionView reloadData];
Stone Preston
42,016 Pointsok. so thats why its not working. Is there any reason you arent using that photos array? why are you using that imagesArray ivar in the first place? I would just use that photos property and set it instead of using those ivars. (although you may have some use in mind for them i dont know)
self.photos = objects;
NSLog(@"images array objects %@", self.photos);
[self.collectionView reloadData];
and then modify your collectionView delegate methods to use self.photos instead of your ivar
Jack Ryder
7,286 Pointsok i've made that change and changed the delegate methods as far as I can see but still no images displaying, any thoughts?
#import "JRViewController.h"
#import "PhotoCell.h"
#import <Parse/Parse.h>
#import "FriendsViewController.h"
@interface JRViewController ()
@end
@implementation JRViewController
- (void)viewDidLoad
{
[super viewDidLoad];
PFUser *currentUser = [PFUser currentUser];
if (currentUser) {
NSLog(@"Current User: %@", currentUser.username);
}
else {
[self performSegueWithIdentifier:@"Segue1" sender:self];
}
[self refresh];
self.edgesForExtendedLayout = UIRectEdgeNone;
UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc]init];
[layout setItemSize:CGSizeMake(306.0, 306.0)];
[layout setMinimumInteritemSpacing:150.0];
[layout setMinimumLineSpacing:130.0];
UICollectionView *collectionView = [[UICollectionView alloc]initWithFrame:self.view.frame collectionViewLayout:layout];
//[collectionView setDataSource:self];
[collectionView setDelegate:self];
[collectionView registerClass:[PhotoCell class] forCellWithReuseIdentifier:@"photo"];
[self.view addSubview:collectionView];
[collectionView setBackgroundColor:[UIColor whiteColor]];
}
-(NSInteger) collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
return[self.photos count];
}
- (UICollectionViewCell *) collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
PhotoCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"photo" forIndexPath:indexPath];
cell.backgroundColor = [UIColor whiteColor];
PFObject *imageObject = [self.photos objectAtIndex:indexPath.row];
PFFile *imageFile = [imageObject objectForKey:@"file"];
[imageFile getDataInBackgroundWithBlock:^(NSData *data, NSError *error) {
if (!error){
NSLog(@"is there any data? %@", data);
cell.imageView.image = [UIImage imageWithData:data];
[self.collectionView reloadData];
}
else {
NSLog(@"no data!");
}
}];
return cell;
}
-(void)refresh{
PFUser *currentUser = [PFUser currentUser];
if (currentUser){
self.friendsRelation = [[PFUser currentUser] objectForKey:@"friendsRelation"];
PFQuery *query = [self.friendsRelation query];
[query orderByAscending:@"username"];
[query findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
if (error) {
NSLog(@"error: %@ %@", error, [error userInfo]);
}
else {
self.friends = objects;
NSLog(@"holla %@", self.friends);
PFQuery *queryFriends = [PFQuery queryWithClassName:@"Posts"];
[queryFriends whereKey:@"senderName" matchesKey:@"username" inQuery:query];
[queryFriends findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
if (error) {
NSLog(@"error: %@ %@", error, [error userInfo]);
}
else {
self.photos = objects;
NSLog(@"photos objects %@", self.photos);
[self.collectionView reloadData];
}
}];
}
}];
}
else {
NSLog(@"woops no user");
}
}
- (IBAction)logout:(id)sender {
[PFUser logOut];
[self performSegueWithIdentifier:@"Segue1" sender:self];
}
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([segue.identifier isEqualToString:@"Segue1"]) {
[segue.destinationViewController setHidesBottomBarWhenPushed:YES];
}
}
@end
cheers
Jack Ryder
7,286 PointsStill not logging the data either
Stone Preston
42,016 Pointsok try logging the objects array as well
self.photos = objects;
NSLog(@"photos array %@", self.photos);
NSLog(@"objects array %@", objects);
[self.collectionView reloadData];
if the objects array works and the photos doesnt thats very strange.
Jack Ryder
7,286 Pointsi can log both self.photos and objects, when i say data i mean in the cellForItemAtIndexPath method the data in there isn't logged.
PFObject *imageObject = [cell.photo objectAtIndex:indexPath.row];
PFFile *imageFile = [imageObject objectForKey:@"file"];
[imageFile getDataInBackgroundWithBlock:^(NSData *data, NSError *error) {
if (!error){
NSLog(@"is there any data? %@", data);
cell.imageView.image = [UIImage imageWithData:data];
[self.collectionView reloadData];
}
else {
NSLog(@"no data!");
}
}];
Also i was wondering does my PhotoCell file need to be changed at all?
Jack Ryder
7,286 Pointsneither is the "no data!" log
Stone Preston
42,016 PointsThis could be the culprit:
PFObject *imageObject = [cell.photo objectAtIndex:indexPath.row];
should probably be
PFObject *imageObject = [self.photos objectAtIndex:indexPath.row];
Jack Ryder
7,286 Pointssorry that's just me messing around and trying different things to solve it, i just changed that a minute ago but originally it was self.photos. still not working!
Stone Preston
42,016 Pointsok log your imageObject and file before you attempt to get its data and make sure they are being set:
PFObject *imageObject = [cell.photo objectAtIndex:indexPath.row];
NSLog(@"image object: %@", imageObject);
PFFile *imageFile = [imageObject objectForKey:@"file"];
NSLog(@"image file: %@", imageFile);
[imageFile getDataInBackgroundWithBlock:^(NSData *data, NSError *error) {
Jack Ryder
7,286 Pointsno log is appearing at all, even when I'm not logging the imageObject just plain text...
Stone Preston
42,016 Pointsso are you sure your delegate methods are even running? they might not be. in that case somethings goin on with your delegate.
Jack Ryder
7,286 Pointsnot logging anything to the console in that entire method
Stone Preston
42,016 Pointsalright so it appears your delegate methods are not being called. You are gonna need to figure out why thats the case.
Jack Ryder
7,286 Pointsany common reasons why this may be the case?
Stone Preston
42,016 Pointsforgetting to add <UICollectionViewDelegate> ( you have that) 0r forgetting to set the delegate (you did) maybe try adding in that line you removed earlier
[collectionView setDataSource:self];
[collectionView setDelegate:self];
``
maybe that was it
Jack Ryder
7,286 Pointsyeah already tried that but still no luck...
Jack Ryder
7,286 Pointsdoes my PhotoCell file not impact on this in any way?
#import "PhotoCell.h"
#import <Parse/Parse.h>
#import "JRCameraViewController.h"
#import "JRViewController.h"
@implementation PhotoCell
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
// Initialization code
self.imageView = [[UIImageView alloc] init];
[self.contentView addSubview:self.imageView];
UILabel *usernameLabel = [[UILabel alloc]initWithFrame:CGRectMake(10,0, 100, 50)];
usernameLabel.text = [[PFUser currentUser]username];
[self.contentView addSubview:usernameLabel];
UILabel *timeLabel = [[UILabel alloc]initWithFrame:CGRectMake(270,0, 100, 50)];
UIImageView *clock = [[UIImageView alloc]initWithFrame:CGRectMake(-15, 18, 14, 14)];
[clock setImage:[UIImage imageNamed:@"clock2"]];
[timeLabel addSubview:clock];
timeLabel.text = @"1h";
[self.contentView addSubview:timeLabel];
UILabel *likeButton = [[UILabel alloc]initWithFrame:CGRectMake(10, 355, 30, 30)];
UIImageView *like = [[UIImageView alloc]initWithFrame:CGRectMake(-1, 22, 20, 20)];
[like setImage:[UIImage imageNamed:@"star1"]];
[likeButton addSubview:like];
likeButton.text = @"67";
likeButton.textColor = [UIColor colorWithRed:0.894 green:0.169 blue:0.259 alpha:1.0];
[self.contentView addSubview:likeButton];
//need if statement here to decide whether to show a timer or a lock icon
// UILabel *timerButton = [[UILabel alloc]initWithFrame:CGRectMake(270, 355, 30, 30)];
// UIImageView *timer = [[UIImageView alloc]initWithFrame:CGRectMake(5, 25, 20, 20)];
// [timer setImage:[UIImage imageNamed:@"timericon"]];
// [timerButton addSubview:timer];
// timerButton.text = @"10h";
// timerButton.textColor = [UIColor colorWithRed:0.894 green:0.169 blue:0.259 alpha:1.0];
// [self.contentView addSubview:timerButton];
UILabel *lockLabel = [[UILabel alloc]initWithFrame:CGRectMake(270, 355, 30, 30)];
UIImageView *lock = [[UIImageView alloc]initWithFrame:CGRectMake(-5, 12, 30, 30)];
[lock setImage:[UIImage imageNamed:@"lockicon1"]];
[lockLabel addSubview:lock];
[self.contentView addSubview:lockLabel];
}
return self;
}
-(void) layoutSubviews {
[super layoutSubviews];
//make the imageview fill the cell -> add labels to cell to display usernames
self.imageView.frame = CGRectMake(0, 50, self.frame.size.width, 300);
}
@end
Stone Preston
42,016 Pointsyour photocell subclass really only effects the look of the cell. It doesnt really effect your controller at all and why the delegate methods arent running.
Jack Ryder
7,286 Pointsin terms of methods numberOfItemsInSection is getting called but cellForItemAtIndexPath is not, does this help in any way...?
Stone Preston
42,016 Pointsyes that does help. See my answer below.
Stone Preston
42,016 Pointstry changing the value of your layout sizes to something like this:
layout.itemSize = CGSizeMake(106, 106);
layout.minimumInteritemSpacing = 1.0;
layout.minimumLineSpacing = 1.0;
it could be that the sizes your specifying currently are too large. If the cells are too large and not visible in the collectionViews bounds the cell will not be created and the delegate method will not run
Jack Ryder
7,286 Pointstried that and resized the images that are uploaded to Parse so that they're within it and still no solution. Can i check when i log self.photos to the console i'm seeing this: "<Posts:Mxq2uQ9kPs:(null)> {\n file = \"<PFFile: 0x17826c8c0>\";\n fileType = image;\n friends = (\n \"<PFUser:TlB9nfXOCJ:(null)> {\n}\"\n );\n senderId = 0ISPHlKPDX;\n senderName = jack2;\n}" this is a manageable format isn't it?
Stone Preston
42,016 Pointsyeah that looks correct. I really dont know whats going on im sorry to say. I dont know why that delegate method wouldnt run. What exactly does the following line do?
self.edgesForExtendedLayout = UIRectEdgeNone;
Jack Ryder
7,286 Pointsthat's a quick fix for the nav bar to not overlap the cells, just tried replacing [self.photos count]; in numberOfItemsInSection with a number and that allows the cellForItemAtIndexPath method to run although it doesn't have any data in it...
Jack Ryder
7,286 PointsStone Preston could the problem be that by the time my self.photos object and the block has ran asynchronously everything else has ran already? That's what it looks like with my logging in the console
Stone Preston
42,016 Pointsno, thats the reason you call
[self.collectionView reloadData];
that will call all the delegate methods again and reload the collection view.
Jack Ryder
7,286 Pointsalso my self.photos is full of objects in the method but when i try log it in viewdidLoad right after the method has been called its empty ??
Jack Ryder
7,286 PointsStone Preston managed to get it working, however, its adding a sub view to the cell every time cellForItemAtIndex path is called as a result the cells are showing various images and generally corrupted. Any ideas on where i could move the adding of the subview to the cell and how?
#import "JRViewController.h"
#import "PhotoCell.h"
#import <Parse/Parse.h>
#import "FriendsViewController.h"
@interface JRViewController ()
@end
@implementation JRViewController
-(void)refreshCollectionView {
NSLog(@"REFRESHING COLLECTION VIEW");
NSLog(@"OBJETS COUNT: %ld", [self.photos count]);
UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc]init];
[layout setItemSize:CGSizeMake(300.0, 300.0)];
[layout setMinimumInteritemSpacing:80.0];
[layout setMinimumLineSpacing:100.0];
UICollectionView *collectionView = [[UICollectionView alloc]initWithFrame:self.view.frame collectionViewLayout:layout];
[collectionView setDataSource:self];
[collectionView setDelegate:self];
[collectionView registerClass:[PhotoCell class] forCellWithReuseIdentifier:@"photo"];
[self.view addSubview:collectionView];
[collectionView setBackgroundColor:[UIColor whiteColor]];
}
- (void)viewDidLoad
{
[super viewDidLoad];
PFUser *currentUser = [PFUser currentUser];
if (currentUser) {
NSLog(@"Current User: %@", currentUser.username);
}
else {
[self performSegueWithIdentifier:@"Segue1" sender:self];
}
self.photos = [[NSArray alloc]init];
self.friends = [[NSArray alloc]init];
self.edgesForExtendedLayout = UIRectEdgeNone;
if (currentUser){
self.friendsRelation = [[PFUser currentUser] objectForKey:@"friendsRelation"];
PFQuery *query = [self.friendsRelation query];
[query orderByAscending:@"username"];
[query findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
if (error) {
NSLog(@"error: %@ %@", error, [error userInfo]);
}
else {
self.friends = objects;
NSLog(@"we have some friends %@", self.friends);
PFQuery *queryFriends = [PFQuery queryWithClassName:@"Posts"];
[queryFriends whereKey:@"senderName" matchesKey:@"username" inQuery:query];
[queryFriends findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
if (error) {
NSLog(@"error: %@ %@", error, [error userInfo]);
}
else {
self.photos = objects;
NSLog(@"photos objects %@", self.photos);
// [self performSelectorOnMainThread:@selector(refreshCollectionView) withObject:nil waitUntilDone:NO];
dispatch_async(dispatch_get_main_queue(), ^
{
[self refreshCollectionView];
});
}
}];
}
}];
}
else {
NSLog(@"woops no user");
}
NSLog(@"is self.photos empty here? %@", self.photos);
}
-(NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView {
return 1;
}
-(NSInteger) collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
NSLog(@"we're in numberOfItemsInSection! %ld items", [self.photos count]);
return [self.photos count];
}
- (UICollectionViewCell *) collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
NSLog(@"we're in the cellForItemAtIndexPath method!");
PhotoCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"photo" forIndexPath:indexPath];
cell.backgroundColor = [UIColor grayColor];
PFObject *imageObject = [self.photos objectAtIndex:indexPath.row];
NSLog(@"do we have an imageObject?...%@", imageObject);
PFFile *imageFile = [imageObject objectForKey:@"file"];
PFImageView *parseImageView = [[PFImageView alloc]initWithFrame:cell.frame];
[cell addSubview:parseImageView];
[parseImageView setFile:imageFile];
[parseImageView loadInBackground];
[self.collectionView reloadData];
return cell;
}
- (IBAction)logout:(id)sender {
[PFUser logOut];
[self performSegueWithIdentifier:@"Segue1" sender:self];
}
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([segue.identifier isEqualToString:@"Segue1"]) {
[segue.destinationViewController setHidesBottomBarWhenPushed:YES];
}
}
@end
Stone Preston
42,016 PointsI thought you were using a custom subclass of UICollectionViewCell? if you are using a subclass that contains an imageView in addition to adding an imageView here in cellForItem that could be causing the problems
Jack Ryder
7,286 Pointsall sorted finally! yeah used a PFImageView in my custom cell which did the trick, thanks for your help!
Jack Ryder
7,286 PointsJack Ryder
7,286 Points