UICollectionViewCell imageView - ios6

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.

Related

prepareForSegue is not called from UITableViewController

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.

No lazy/delayed loading on UICollectionView inside an UITableViewCell

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

Basic iphone app, and breaking point error

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

Rotating a UIViewController to Portrait when in Device Landscape in iOS 6

I am working with a Custom Video Camera. To make recording easy I setup the camera an it's overlay to be in portrait, but look as if it was in Landscape. This works for me as I want the videos to be taken width long due to the nature of the project. Currently I'm having a challenge with iOS 6 to get my view controllers to rotate to portrait, and portraitUpsideDown when the device is rotated to landscapeLeft and landscapeRight. Is there anyway in iOS 6 to tell the view controller to rotate to portrait when the device rotates to landscape? Previously I would do this with shouldAutoRotateToOrientation
Currently I'm toying with these methods
- (BOOL)shouldAutorotate {
return YES;
}
- (NSUInteger)supportedInterfaceOrientationsForWindow {
return UIInterfaceOrientationMaskPortrait;
}
I've looked at a lot of the other documentation on stack overflow about these changes in iOS6 but haven't yet found a solution to this problem.
We were able to get working. We did for Landscape but you can do it for Portrait by modifying the code bellow:
First in the interface (this is only partial b/c of company policies i can't show you everything):
#interface YourViewController : UIViewController <UITableViewDelegate, UITableViewDataSource>
{
UITableView *myTableView;
CGAffineTransform _originalTransform;
CGRect _originalBounds;
CGPoint _originalCenter;
}
#property (nonatomic, retain) UITableView *myTableView;
#end
Next here is the implementation:
#implementation YourViewController
#synthesize myTableView;
- (void)loadView {
UIView *viewContainer = [[UIView alloc] initWithFrame:[[UIScreen mainScreen] applicationFrame]];
CGRect tableFrame;
tableFrame.origin.x += 10;
tableFrame.origin.y -= 15;
tableFrame.size.height = 320;
tableFrame.size.width = 460;
// create and configure the table view
myTableView = [[UITableView alloc] initWithFrame:tableFrame style:UITableViewStylePlain];
myTableView.delegate = self;
myTableView.dataSource = self;
myTableView.autoresizesSubviews = YES;
myTableView.scrollEnabled = YES;
myTableView.autoresizingMask = UIViewAutoresizingFlexibleHeight|UIViewAutoresizingFlexibleWidth;
[viewContainer addSubview:myTableView];
self.view = viewContainer;
}
- (void)viewWillAppear:(BOOL)animated {
AppDelegate *appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
_originalTransform = [[appDelegate navController].view transform];
_originalBounds = [[appDelegate navController].view bounds];
_originalCenter = [[appDelegate navController].view center];
CGAffineTransform landscapeTransform = CGAffineTransformMakeRotation(degreesToRadian(3.14/2));
//landscapeTransform = CGAffineTransformTranslate (landscapeTransform, +80.0, +100.0);
[[appDelegate navController].view setTransform:landscapeTransform];
[appDelegate navController].view.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
[appDelegate navController].view.bounds = CGRectMake(0.0, 0.0, 480.0, 320.0);
//[appDelegate navController].view.center = CGPointMake (240.0, 160.0);
[UIApplication sharedApplication].statusBarOrientation = UIInterfaceOrientationLandscapeRight;
}
- (void) viewWillDisappear:(BOOL)animated {
AppDelegate *appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
[[appDelegate navController].view setTransform:_originalTransform];
[[appDelegate navController].view setBounds:_originalBounds];
[[appDelegate navController].view setCenter:_originalCenter];
[UIApplication sharedApplication].statusBarOrientation = UIInterfaceOrientationPortrait;
}

Can not setStatusBarOrientaion in IOS6

Orientation status not change when I use UINavigationController.
this is my code:
AppDelegate.h file
#import <UIKit/UIKit.h>
#class MainViewController;
#interface AppDelegate : UIResponder<UIApplicationDelegate>
#property (strong, nonatomic) UIWindow *window;
#property (strong, nonatomic) MainViewController *mainViewController;
#end
AppDelegate.m file
...
-(BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDistionary* launchOptions
{
self.window = [[UIWindow alloc]initWithFrame:[[UIScreen mainScreen]bounds]];
self.mainViewController = [[MainViewController alloc]initWithNibName:#"MainViewController" bundle:nil];
UINavigateionController *navigationController = [[UINavigationController alloc]initWithRootViewController:self.mainViewController];
self.window.rootViewController = navigationController;
[self.window makeKeyAndVisible];
return YES;
}
....
MainViewController.m
...
-(NSUInteger)supportedInterfaceOrientations{
return UIInterfaceOrientationMaskLandscapeLeft;
}
-(UIInterfaceOrientation)preferredInterfaceOrientationForPresentation{
return UIInterfaceOrientationMaskLandscapeLeft;
}
-(BOOL)shouldAutorotate{
return YES;
}
-(void) viewDidAppear:(BOOL)animated {
[UIApplication sharedApplication].statusBarOrientation = UIInterfaceOrientationLandscapeLeft;
[self.navigationController setNavigationBarHidden:YES];
}
...
From iOS 6.0 SDK Release Notes:
The setStatusBarOrientation:animated: method is not deprecated outright. It now works only if the supportedInterfaceOrientations method of the top-most full-screen view controller returns 0. This makes the caller responsible for ensuring that the status bar orientation is consistent.

Resources