I have started iOS app development recently.
I have a problem about segue from UITableViewController to UIViewController.
"prepareForSegue" is not called when a tablecell is clicked.
It seems to me that the code and interface builder settings are fine.
Segue ID is properly set. I also embedded UITableVC in navigationVC, too.
I set the breakpoint in the prepareForSegue, but it does not stop there and no log is generated.
Through researching tips in the Internet, I understand that using didSelectRowAtIndexPath is one of the solutions for my problem.
But I would like to understand the solution by using storyboard.
This might be a basic question, but if someone could give me some tips, it could be very helpful.
thank you,
#interface test2TVC ()
#property(strong,nonatomic) NSArray *items;
#end
#implementation test2TVC
- (void)viewDidLoad
{
[super viewDidLoad];
self.items = #[#"item1", #"item2", #"item3", #"item4",
#"item5", #"item6", #"item7", #"item8"];
}
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
NSLog(#"test log");
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [self.items count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
[self.tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:#"Cell"];
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
cell.textLabel.text = [self.items objectAtIndex:indexPath.row];
return cell;
}
#end
When I use:
[self.tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:CellIdentifier];
in viewDidLoad
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath] in cellForRowAtIndexPath
prepareForSegue will not be called.
When I remove registerClass line in viewDidLoad, and
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
in cellForRowAtIndexPath, prepareForSegue will be called, other setting are all same.
Make sure that you have embedded navigation controller your UITableViewController in Mainstoryboard. or try to embed navigation controller in rootViewController of your project. Then set reuse identifier in tableviewcell. Any problem the please share it.
Related
I have a view controller with 2 arrays, one for normal results; the other for filtered/search results based off text entry.
Only one cell can have the UITableViewCellAccessoryCheckmark at a time.
My problem can be described thusly;
IE:
View controller is fed a Venue object; and is marked with
UITableViewCellAccessoryCheckmark. This is expected, and correct.
User types in a search query, the search results array is used;
however the UITableViewCellAccessoryCheckmark is no longer on the
Venue that was previously checked in step 1.
I am not sure why its not checking the cell.
Visual examples;
Original view. Cobo Arena is the pre-selected venue
-
When typing; The checkmark is not in the right place
-
More typing: The checkmark is now gone
-
The code is below
- (void) configureCell:(UITableViewCell *)cell atIndexPath:(NSIndexPath *)indexPath
{
FCVenue *venue;
if (self.isSearching)
{
venue = [self.searchResults objectAtIndex:indexPath.row];
}
else
{
venue = [self.venues objectAtIndex:indexPath.row];
}
if ([indexPath isEqual:self.selectedIndexPath])
{
cell.accessoryType = UITableViewCellAccessoryCheckmark;
}
else
{
cell.accessoryType = UITableViewCellAccessoryNone;
}
cell.textLabel.text = [NSString stringWithFormat:#"%#", venue.name];
cell.detailTextLabel.text = [NSString stringWithFormat:#"%#", venue.location];
}
-(NSIndexPath *)tableView:(UITableView *)tableView willSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[self.tableView cellForRowAtIndexPath:self.selectedIndexPath].accessoryType = UITableViewCellAccessoryNone;
self.selectedIndexPath = indexPath;
[self.tableView reloadRowsAtIndexPaths:#[self.selectedIndexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
return indexPath;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[tableView deselectRowAtIndexPath:indexPath animated:YES];
FCVenue *venue;
if (self.searching)
{
venue = [self.searchResults objectAtIndex:indexPath.row];
}
else
{
venue = [self.venues objectAtIndex:indexPath.row];
}
self.selectedVenue = venue;
// This method fires a completion block and dismisses the view controller
if (self.completionBlock)
{
self.completionBlock( self, self.selectedVenue );
}
[self.navigationController dismissViewControllerAnimated:YES completion:^{
}];
}
That's happening because you are storing the index of the full table to display the checkmark. Instead you should compare the FCVenue object to see if that is the one checked or not.
So the code should be something like this, it is not tested though:
- (void) configureCell:(UITableViewCell *)cell atIndexPath:(NSIndexPath *)indexPath
{
FCVenue *venue;
if (self.isSearching)
{
venue = [self.searchResults objectAtIndex:indexPath.row];
}
else
{
venue = [self.venues objectAtIndex:indexPath.row];
}
if ([venue isEqual:self.selectedVenue]) // You may want to compare just the id or any other unique property
{
cell.accessoryType = UITableViewCellAccessoryCheckmark;
// if you opt for keeping the selectedIndexPath property you need to refresh it here.
}
else
{
cell.accessoryType = UITableViewCellAccessoryNone;
}
cell.textLabel.text = [NSString stringWithFormat:#"%#", venue.name];
cell.detailTextLabel.text = [NSString stringWithFormat:#"%#", venue.location];
}
-(NSIndexPath *)tableView:(UITableView *)tableView willSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
//[self.tableView cellForRowAtIndexPath:self.selectedIndexPath].accessoryType = UITableViewCellAccessoryNone;
// Here you may want to do a loop over all the possible index path to clean the state or keep storing the selected indexPath just to clear the mark when the selected venue changes.
FCVenue *venue;
if (self.searching)
{
venue = [self.searchResults objectAtIndex:indexPath.row];
}
else
{
venue = [self.venues objectAtIndex:indexPath.row];
}
self.selectedVenue = venue;
[self.tableView reloadRowsAtIndexPaths:#[indexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
return indexPath;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[tableView deselectRowAtIndexPath:indexPath animated:YES];
// This method fires a completion block and dismisses the view controller
if (self.completionBlock)
{
self.completionBlock( self, self.selectedVenue );
}
[self.navigationController dismissViewControllerAnimated:YES completion:^{
}];
}
In any case the general idea is that you need to tie the venue with the check and not with at indexPath as the indexPath will change with the search.
I'm working on a weird issue right now. My Apps Deployment Target is set to iOS6, so I want to support both iOS6 and iOS7.
I just have a simple UITableView, in which the user can select the preferred notification sound.
The code for - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath is:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"CheckmarkCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
[cell setTintColor:[UIColor redColor]];
if (indexPath.section == 0){
cell.textLabel.text = [_availableSounds objectAtIndex:indexPath.row];
if (indexPath.row == _checkedSoundIndexPath.row) {
cell.accessoryType = UITableViewCellAccessoryCheckmark;
}
}
else {
// Unrelated, another settings cell
cell.accessoryType = UITableViewCellAccessoryNone;
cell.selectionStyle = UITableViewCellSelectionStyleNone;
}
return cell;
}
My - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath looks like the following:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
if (indexPath.section != 0) {
return;
}
[self.tableView deselectRowAtIndexPath:indexPath animated:YES];
[[self.tableView cellForRowAtIndexPath:indexPath] setAccessoryType:UITableViewCellAccessoryCheckmark];
if (_checkedSoundIndexPath != indexPath) {
[[self.tableView cellForRowAtIndexPath:_checkedSoundIndexPath] setAccessoryType:UITableViewCellAccessoryNone];
}
_checkedSoundIndexPath = indexPath;
}
The problem is that an iOS7 iPhone won't show the checkmark as expected. Running the same code on an iOS6 iPhone works as expected. I tried to insert [cell setTintColor:[UIColor redColor]]; but without any luck. Even if I remove all AccessoryType related code and add the checkmark in my storyboard nothing appears. See screenshots below (first is iOS6 and second is iOS5).
Does anyone have an idea ? Or is it a bug in iOS7 ?
Thanks in advance !
Edit:
Even if I make a new simple UITableViewController, with just 5 cells with the Accessory set to UITableViewAccessoryTypeCheckmark, the Checkmarks won't appear on iOS7.
I had a similar problem and I solved this issues changing the tint color of the uitableview
I changed the tintcolot of uitable by InterfaceBuilder to Default color
or
tableView.tintColor = [UIColor blackColor];
I had the exact same problem as you are for a long time.
In my case I implemented some appearance tweaks. And one of them was
[[UIView appearance] setTintColor:[UIColor whiteColor]];
Try to find in your project global things like that.
In my application it working perfect,check it
//take it in .h file mutable arSelectedRows;
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
[cell setSelectionStyle:UITableViewCellSelectionStyleGray];
//Do anything you want for cell here
if([arSelectedRows containsObject:indexPath]) {
cell.accessoryType = UITableViewCellAccessoryCheckmark;
}
else {
cell.accessoryType = UITableViewCellAccessoryNone;
}
return cell;
}
#pragma mark - Table view delegate
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
if(cell.accessoryType == UITableViewCellAccessoryNone) {
cell.accessoryType = UITableViewCellAccessoryCheckmark;
[arSelectedRows addObject:indexPath];
}
else {
cell.accessoryType = UITableViewCellAccessoryNone;
[arSelectedRows removeObject:indexPath];
}
NSLog(#"id are here :%#",arSelectedIDs);
[tableView deselectRowAtIndexPath:indexPath animated:YES];
}
may be ,it will helpful.
No, There is No Problem with UITableViewCellAccessoryCheckmark in iOS 7,Make sure you have implemented correct logic for it.
I think the problem is with your checksoundIndexpath, please check whether it has a correct indexpath, Or First check with hardcoded indexpath.
you are not initializing the checksoundindxpath.
Also I noticed you are not assigning the selected row indexpath to _checkSoundIndexpath, Only you are checking if both indexpaths(current indexpaths and _checksoundindexpath) are equal, But if they are different then you should assign the selected indedxpath to _checksound indexpath.
I can solve this problem by set tint color for Cell
It didnt show because cell tint in white ,and cell selectionstyle is none
cell.tintColor = [UIColor blackColor];
if(cell.selected){
[cell setAccessoryType:UITableViewCellAccessoryCheckmark];
}else{
[cell setAccessoryType:UITableViewCellAccessoryNone];
}
I would rather reload tableview (preferably only the affected rows - using reloadRowsAtIndexPaths) after settings appropriate data in didSelectRowAtIndexPath: method.
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
// Other logic..
[tableView deselectRowAtIndexPath:indexPath animated:NO]; // Would like to look for an alternative method to avoid this refresh??
NSMutableArray *reloadArray = [NSMutableArray arrayWithCapacity:2];
[reloadArray addObject:indexPath];
[reloadArray addObject:_checkedSoundIndexPath];
self.checkedSoundIndexPath = indexPath; // Should set this before reload
[tableView reloadRowsAtIndexPaths:reloadArray withRowAnimation:UITableViewRowAnimationAutomatic];
}
And, most importantly, add these lines in cellForRowAtIndexPath: method -
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
// All your other code for this section followed by these lines...
if([_checkedSoundIndexPath compare:indexPath] == NSOrderedSame) {
cell.accessoryType = UITableViewCellAccessoryCheckmark;
}
else {
cell.accessoryType = UITableViewCellAccessoryNone;
}
// Other sections code
return cell;
}
I know the original question uses a simple UITableViewCell but this might work for someone else with a custom table view cell.
I have a custom UITableViewCell subclass. I tried everything but the checkmark won't show. Eventually I realised that I overrode layoutSubviews but forgot to call [super layoutSubviews]. Which meant the checkmark would not show correctly.
- (void)layoutSubviews
{
[super layoutSubviews];
//...custom layout here
}
I have a UITableViewCell with an UICollectionView inside it. My custom UITableViewCell is responsible for the datasource and methods for the UICollectionView. All works perfectly except when I add some logging to the cellForItemAtIndexPath I see that all UICollectionViewCells will be loaded at once. So there goes my lazy/delayed loading when scrolling down.
Here is my logging in the custom UITableViewCell
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
NSLog(#"Loading cell: %i", indexPath.row);
}
The tableViewCell height is automaticaly calculated based on the items the UICollectioNView needs to handle. So in the tableview method of my ViewController:
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
//return dynamically the height based on the items to show in the collectionview.
}
So I guess this is my problem and reason why it doesn't do lazy loading. Is there an easy fix for this ? Or is this the way:
Source: http://ashfurrow.com/blog/putting-a-uicollectionview-in-a-uitableviewcell
By this the lazy loading will only be handled by the UITableView and not the UICollectionView.
Here is the full code of my custom UITableViewCell, but as you will see this is really nothing special.
#implementation PeopleJoinedThisPlaceCell
#synthesize people = _people;
- (void)awakeFromNib
{
collectionView.delegate = self;
collectionView.dataSource = self;
collectionView.backgroundColor = [UIColor clearColor];
}
- (void)setPeople:(NSArray *)people
{
_people = people;
[collectionView reloadData];
}
#pragma mark - CollectionViewController delegate methods
- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView
{
if(_people == NULL) return 0;
return 1;
}
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section
{
if(_people == NULL) return 0;
return _people.count;
}
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView_ cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
NSLog(#"Loading cell: %i", indexPath.row);
ImageCollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:#"People" forIndexPath:indexPath];
PFObject *userPlace = [_people objectAtIndex:indexPath.row];
PFUser *user = [userPlace objectForKey:UserClassName];
[cell.BackgroundImageView setImage:[UIImage imageNamed:#"photo-big-bg"]];
[cell.ImageLoader startAnimating];
[[UserPhotos sharedInstance] getCachedSmallPhotoForUser:user withBlock:^(UIImage *image, NSError *error) {
[cell.ImageView setImage:image];
[cell.ImageLoader stopAnimating];
}];
return cell;
}
- (void)collectionView:(UICollectionView *)collectionView_ didSelectItemAtIndexPath:(NSIndexPath *)indexPath
{
PFObject *userPlace = [_people objectAtIndex:indexPath.row];
[_delegate gotoUserProfile:userPlace];
}
#end
I'm trying to learn ios coding and trying to make a foodDiary application.. I've used empty project file and then added the storyboard,view controller and table view controller
when I run my program the tableView Menu shows up with the elements in it, then when I press the + button a view controller shows up which has a textfield and a button inside.. when I type in something and press the button my program crushes and I get breakpoint error,
I get error here:
- (IBAction)addFoodButton:(id)sender {
NSString *newFood = [addFoodText text];
[foodTableViewController addFood:newFood];
[[self presentingViewController] dismissViewControllerAnimated:YES completion:nil];
}
my partial coding are:
DAYfoodTableViewController.h
#import <UIKit/UIKit.h>
#interface DAYfoodTableViewController : UITableViewController
#property (nonatomic, strong) NSMutableArray *foodArray;
-(void) addFood:(NSString *) newFood;
#end
DAYfoodTableViewController.m
#import "DAYfoodTableViewController.h"
#import "DAYaddFoodViewController.h"
#interface DAYfoodTableViewController ()
#end
#implementation DAYfoodTableViewController
#synthesize foodArray;
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
DAYaddFoodViewController *addFoodViewController = [segue destinationViewController];
[addFoodViewController setFoodTableViewController:self];
}
-(void) addFood:(NSString *)newFood
{
[foodArray addObject:newFood];
[[self tableView] reloadData];
}
- (id)initWithStyle:(UITableViewStyle)style
{
self = [super initWithStyle:style];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
foodArray=[[NSMutableArray alloc] initWithObjects:#"Pizza",#"Chips",#"Sandwiches",#"Hot Dogs", nil];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#pragma mark - Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [foodArray count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"BasicCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
int rowNumber=[indexPath row];
NSString *food=[foodArray objectAtIndex:rowNumber];
[[cell textLabel] setText:food];
return cell;
}
/*
// Override to support conditional editing of the table view.
- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath
{
// Return NO if you do not want the specified item to be editable.
return YES;
}
*/
// Override to support editing the table view.
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
{
if (editingStyle == UITableViewCellEditingStyleDelete) {
[foodArray removeObjectAtIndex:[indexPath row] ];
[tableView deleteRowsAtIndexPaths:#[indexPath] withRowAnimation:UITableViewRowAnimationFade ];
/*
or (by asim)
if (editingStyle == UITableViewCellEditingStyleDelete) {
[foodArray removeObjectAtIndex:[indexPath row] ];
[[self tableView] reloadData];
}
*/
}
else if (editingStyle == UITableViewCellEditingStyleInsert) {
// Create a new instance of the appropriate class, insert it into the array, and add a new row to the table view
}
}
/*
// Override to support rearranging the table view.
- (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)fromIndexPath toIndexPath:(NSIndexPath *)toIndexPath
{
}
*/
/*
// Override to support conditional rearranging of the table view.
- (BOOL)tableView:(UITableView *)tableView canMoveRowAtIndexPath:(NSIndexPath *)indexPath
{
// Return NO if you do not want the item to be re-orderable.
return YES;
}
*/
#pragma mark - Table view delegate
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
// Navigation logic may go here. Create and push another view controller.
/*
<#DetailViewController#> *detailViewController = [[<#DetailViewController#> alloc] initWithNibName:#"<#Nib name#>" bundle:nil];
// ...
// Pass the selected object to the new view controller.
[self.navigationController pushViewController:detailViewController animated:YES];
*/
}
#end
DAYaddFoodTableViewController.h
#import <UIKit/UIKit.h>
#import "DAYfoodTableViewController.h"
#interface DAYaddFoodViewController : UIViewController
#property (nonatomic, weak) DAYfoodTableViewController *foodTableViewController;
- (IBAction)addFoodButton:(id)sender;
#property (weak, nonatomic) IBOutlet UITextField *addFoodText;
#end
DAYaddFoodTableView.m
#import "DAYaddFoodViewController.h"
#interface DAYaddFoodViewController ()
#end
#implementation DAYaddFoodViewController
#synthesize foodTableViewController;
#synthesize addFoodText;
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (IBAction)addFoodButton:(id)sender {
NSString *newFood = [addFoodText text];
[foodTableViewController addFood:newFood];
[[self presentingViewController] dismissViewControllerAnimated:YES completion:nil];
}
#end
The weird thing is that when the program crushes and I re-run the program through the simulator it works perfectly..
what could cause this problem? thanks
It appears from the partial code listing that you didn't finish all of the tasks required. You have made your initial controller to be a delegate, but not defined the delegate as a property in your header file or synthesized it in your implementation file. Additionally, you did not add it to the second controller, but are attempting to call the optional method of your first controller, and calling it incorrectly. I think that is why it is crashing.
Seques, which you've used, coupled with notifications, can accomplish many of the things which delegation can.
You need to study up on notification and seques... which allows you to pass data back and forth between controllers. And, in your case you need to.
Watch the appropriate WWDC videos, and work through some tutorials, and these are some of the best... http://www.raywenderlich.com/tutorials
Code works fine until I changed UIViewController with tableView to UICollectionViewController.
Now all cells shows same image, sometimes it flipping to nil.
However textLabels are OK.
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"TourGridCell";
TourGridCell *cell = (TourGridCell *)[collectionView dequeueReusableCellWithReuseIdentifier:CellIdentifier forIndexPath:indexPath];
Guide *guideRecord = [self.fetchedResultsController objectAtIndexPath:indexPath];
cell.titleLabel.text = [guideRecord.name uppercaseString];
cell.titleLabel.backgroundColor = [UIColor clearColor];
if ([guideRecord.sights count] > 0) {
if ([[guideRecord.sights objectAtIndex:0]valueForKey:#"thumbnail"]) {
cell.imageView.image = [UIImage drawImage:[[guideRecord.sights objectAtIndex:0]valueForKey:#"thumbnail"] inImage:[UIImage imageNamed:#"MultiplePhotos"] inRect:CGRectMake(11, 11, 63, 63)];
}else {
cell.imageView.image = [UIImage imageNamed:#"placeholder2"];
}
NSMutableString *sightsSummary = [NSMutableString stringWithCapacity:[guideRecord.sights count]];
for (Sight *sight in guideRecord.sights) {
if ([sight.name length]) {
if ([sightsSummary length]) {
[sightsSummary appendString:#", "];
}
[sightsSummary appendString:sight.name];
}
}
if ([sightsSummary length]) {
[sightsSummary appendString:#"."];
}
cell.sightsTextLabel.text = sightsSummary;
cell.detailTextLabel.text = [NSString stringWithFormat:NSLocalizedString(#"%i", nil) , [guideRecord.sights count]];
cell.detailTextLabel.hidden = NO;
// cell.textLabel.alpha = 0.7;
NSPredicate *enabledSightPredicate = [NSPredicate predicateWithFormat:#"notify == YES"];
NSArray *sightsEnabled = [[[guideRecord.sights array] filteredArrayUsingPredicate:enabledSightPredicate]mutableCopy];
NSPredicate *visitedSightPredicate = [NSPredicate predicateWithFormat:#"visited == YES"];
NSArray *sightsVisited = [[[guideRecord.sights array] filteredArrayUsingPredicate:visitedSightPredicate]mutableCopy];
if ([sightsEnabled count] > 0)
{
NSLog(#"green_badge");
cell.notifyIV.image = [UIImage imageNamed:#"green_badge"];
}
else if (sightsVisited.count == 0) {
NSLog(#"new_badge");
cell.notifyIV.image = [UIImage imageNamed:#"new_badge"];
}
else
{
cell.notifyIV.image = nil;
}
}
else {
cell.notifyIV.hidden = YES;
// cell.textLabel.textColor = RGB(0, 50, 140);
cell.detailTextLabel.hidden = YES;
cell.sightsTextLabel.text = nil;
}
return cell;
}
Cell set up in storyboard,
// TourGridCell.h
#import <UIKit/UIKit.h>
#interface TourGridCell : UICollectionViewCell
#property (weak, nonatomic) IBOutlet UILabel *titleLabel;
#property (weak, nonatomic) IBOutlet UIImageView *imageView;
#property (weak, nonatomic) IBOutlet UIImageView *notifyIV;
#property (weak, nonatomic) IBOutlet UILabel *textLabel;
#property (weak, nonatomic) IBOutlet UILabel *detailTextLabel;
#property (weak, nonatomic) IBOutlet UILabel *sightsTextLabel;
#end
#import "TourGridCell.h"
#implementation TourGridCell
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
// Initialization code
}
return self;
}
/*
// Only override drawRect: if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
- (void)drawRect:(CGRect)rect
{
// Drawing code
}
*/
#end
you may need to provide some more data for it to be possible for others to work out what the problem is. I take it you have checked that at the different times this is called the conditions are being triggered so different images are actually being instantiated and added to your UICollectionViewCell? Also I take it you are aware a UICollectionViewCell doesn't have an image property so you will need to add a property in it's subclass (if you want easy access to the view without the overhead of retrieving it using it's tag ID) and ensure the view is added as a subview ?
I think, given the symptoms you have described, such a problem can occur if you are not adding your sub-views to the UICollectionViewCell's contentView. Apple's collection views have all manner of optimisations to ensure high performance and only the subviews of the UICollectionViewCell's content view (which is itself a sub-view of UICollectionViewCell) will be consistently drawn as you expect.
Though based on what you have provided, I can't be definitive as to if this is the cause of the problem.
#implementation UICollectionViewCellSubView
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
// Initialization code
_imageView = [[UIImageView alloc] initWithFrame:frame];
[self.contentView addSubview:_imageView];
}
return self;
}
- (void)prepareForReuse
{
[super prepareForReuse];
// ensure you do appropriate things
// here for when the cells are recycled
// ...
}
#end
Solution is to nullify image each time in cellForItemAtIndexPath:
cell.imageView.image = nil;
if you are doing custom drawing in your cell, you will need to inform the cell to 'redraw' itself when a cell has been 'reused'. This is perhaps easiest done by implementing the prepareForReuse method in your UICollectionViewCell subclass.
- (void)prepareForReuse {
[super prepareForReuse];
[self setNeedsDisplay];
}
Technically, we probably don't need to include [super prepareForReuse] as the documentation suggests 'The default implementation of this method does nothing'. However, it is good practice, and who knows if Apple will change the default implementation of prepareForReuse in the future.