ActivityIndicator doesn't stop animating nor removes from superview in UICollectionViewCell - objective-c

I am trying to implement UICollectionView and show images. I am using SDWebimage which works perfectly in tableviewcells but when i tried to use it in UICollectionviewCell it doesn't stop and remove activityindicator. It does place the placeholder image if there is no downloaded image. I am not sure what is the difference between tableviewcell and collectionviewcell that might cause this problem.
Here is the code:
-(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"personImageCell";
PersonCollectionViewCell *cell = (PersonCollectionViewCell *)[collectionView dequeueReusableCellWithReuseIdentifier:CellIdentifier forIndexPath:indexPath];
Person *person = [self.fetchedResultsController objectAtIndexPath:indexPath];
NSString *imgURL=[person.imageurl stringByAppendingString:#"?maxheight=300&maxwidth=400"];
UIActivityIndicatorView *activityIndicator = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhite];
activityIndicator.hidesWhenStopped = YES;
activityIndicator.hidden = NO;
[activityIndicator startAnimating];
activityIndicator.center = CGPointMake(cell.ivPersonImage.frame.size.width /2, cell.ivPersonImage.frame.size.height/2);
[cell.ivPersonImage setImageWithURL:[NSURL URLWithString:imgURL] placeholderImage:nil options:SDWebImageProgressiveDownload success:^(UIImage *image, BOOL cached){
[activityIndicator stopAnimating];[activityIndicator removeFromSuperview];
NSLog(#"activity indicator should be removed");
}failure:^(NSError *error){
[activityIndicator stopAnimating];[activityIndicator removeFromSuperview];
cell.ivPersonImage.image = [UIImage imageNamed:#"placeholder.png"];
}];
[cell.ivPersonImage addSubview:activityIndicator];
return cell;
}
UPDATE:
When i do NSLog(#"activity indicator should be removed %#,activityIndicator);
I get this output:
activity indicator should be removed <UIActivityIndicatorView: 0xa520ab0; frame = (65 90; 20 20); hidden = YES; layer = <CALayer: 0xa520b60>>
It shows that UIActivityindicator is hidden but it is still showing on top of the image

It seems that you are reusing cell so there are more then one UIActivityIndicatorViews.
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"personImageCell";
PersonCollectionViewCell *cell = (PersonCollectionViewCell *)[collectionView dequeueReusableCellWithReuseIdentifier:CellIdentifier forIndexPath:indexPath];
Person *person = [self.fetchedResultsController objectAtIndexPath:indexPath];
NSString *imgURL=[person.imageurl stringByAppendingString:#"?maxheight=300&maxwidth=400"];
UIActivityIndicatorView *activityIndicator = [cell.ivPersonImage viewWithTag:10];
if (activityIndicator) [activityIndicator removeFromSuperview];
activityIndicator = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhite];
activityIndicator.hidesWhenStopped = YES;
activityIndicator.hidden = NO;
[activityIndicator startAnimating];
activityIndicator.center = cell.ivPersonImage.center;
activityIndicator.tag = 10;
[cell.ivPersonImage addSubview:activityIndicator];
[cell.ivPersonImage setImageWithURL:[NSURL URLWithString:imgURL] placeholderImage:nil options:SDWebImageProgressiveDownload success:^(UIImage *image, BOOL cached){
[activityIndicator stopAnimating];[activityIndicator removeFromSuperview];
NSLog(#"activity indicator should be removed");
}failure:^(NSError *error){
[activityIndicator stopAnimating];[activityIndicator removeFromSuperview];
cell.ivPersonImage.image = [UIImage imageNamed:#"placeholder.png"];
}];
return cell;
}

Hmm....this is weird..can you try to make sure the activityIndicator is working on the main thread -
[cell.ivPersonImage setImageWithURL:[NSURL URLWithString:imgURL] placeholderImage:nil options:SDWebImageProgressiveDownload success:^(UIImage *image, BOOL cached){
dispatch_async(dispatch_get_main_queue(), ^(void){
[activityIndicator stopAnimating];
[activityIndicator removeFromSuperview];
}
NSLog(#"activity indicator should be removed");
}failure:^(NSError *error){
dispatch_async(dispatch_get_main_queue(), ^(void){
[activityIndicator stopAnimating];
[activityIndicator removeFromSuperview];
}
cell.ivPersonImage.image = [UIImage imageNamed:#"placeholder.png"];
}];
I suspect it is not, that is why it is not stopping its animation.

Create the activity indicator in the ViewDidLoad of current View Controller
UIActivityIndicatorView *spinner = [[UIActivityIndicatorView alloc]initWithFrame:CGRectMake(150, 225, 20, 30)];
[spinner setActivityIndicatorViewStyle:UIActivityIndicatorViewStyleGray];
spinner.color = [UIColor blueColor];
[self.view addSubview:spinner];
Use below code right in the beginning of the function which leads to the activity
[NSThread detachNewThreadSelector:#selector(threadStartAnimating:) toTarget:selfwithObject:nil];
Declare these two methods for starting and stoping the Animation
-(void)threadStartAnimating:(id)data
{
[spinner startAnimating];
}
-(void)threadStopAnimating:(id)data
{
[spinner stopAnimating];
}
Please give feedback as this code is working fine in my own project

Related

Remove UICollectionView cells on edit button

I am using a UICollectionView to retrieve images and labels stored in the Cloud database Parse.
I now need an option that will let me delete a certain image and its corresponding label.
I am looking for something such as the typical iPhone "Edit" button on the top right hand corner which displays a swipe animation with a delete button next to the cell. I'm aware that such a thing can be done on a UITableView through
[[self tableView] setEditing:YES animated:YES];
but I can't seem to find the equivalent for a UICollectionView anywhere.
Any help appreciated, even if it doesn't deal with the deletion from Parse itself, just the editing style on the collection view would be ideal.
Here is how I populate my cells:
- (void)viewDidLoad
{
[super viewDidLoad];
[self retrieveSelectedImages];
}
-(NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView {
return 1;
}
-(NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
return [imageFilesArray count];
}
-(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
static NSString *cellIdentifier = #"myRoomsCell";
MyRoomsCell *cell = (MyRoomsCell *)[collectionView dequeueReusableCellWithReuseIdentifier:cellIdentifier forIndexPath:indexPath];
PFObject *imageObject = [imageFilesArray objectAtIndex:indexPath.row];
PFFile *imageFile = [imageObject objectForKey:#"imageFile"];
cell.loadingSpinner.hidden = NO; //show loading spinner to indicate work is happening until the image loads
[cell.loadingSpinner startAnimating];
// UILabel *label = (UILabel*) [cell viewWithTag:5];
cell.label.text= [imageObject objectForKey:#"roomLabel"]; //set room label as the label stored on parse previously inserted by the user
cell.label.font = [UIFont fontWithName:#"Helvetica-Bold" size:18];
cell.label.textAlignment = NSTextAlignmentCenter;
[imageFile getDataInBackgroundWithBlock:^(NSData *data, NSError *error)
{
if (!error) {
cell.parseImage.image = [UIImage imageWithData:data];
[cell.loadingSpinner stopAnimating];
cell.loadingSpinner.hidden = YES;
}
}];
return cell;
}
-(void) retrieveSelectedImages
{
//parse query where we search the favorites array column and return any entry where the array contains the logged in user objectid
PFQuery *getFavorites = [PFQuery queryWithClassName:#"collectionViewData"];
[getFavorites whereKey:#"selectedImage" equalTo:[PFUser currentUser].objectId];
[getFavorites findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
if (!error)
{
imageFilesArray = [[NSArray alloc] initWithArray:objects];
[roomsCollection reloadData];
}
}];
}
Check out this answer with plenty of code for you to try out: https://stackoverflow.com/a/16190291/1914567
Basically, there is no Apple-provided way to do this.
There are also some really nice libraries. My personal favorite is DraggableCollectionView, and also check out LXReorderableCollectionViewFlowLayout.
-(void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath {
[[Singleton sharedSingleton].selectedProfileArray removeObjectAtIndex:indexPath.row];
[selectCollectionView reloadData];
}

How to show an UIActivityindicator in UICollectionview customcell untill the image downloads at server side?

Can Any one help me how to show the activity indicator until the image for UICollection cell downloads at back end.
In my code the activity indicator is show only for last cell..Don't know where I m making the mistake
Here is my code:
- (collectionCell *)collectionView:(UICollectionView *)collectionView
cellForItemAtIndexPath:(NSIndexPath *)indexPath{
[self.menuCollectionView registerNib:[UINib nibWithNibName:#"collectionCell"
bundle:nil] forCellWithReuseIdentifier:#"CELL"];
collectionCell= [menuCollectionView dequeueReusableCellWithReuseIdentifier:#"CELL"
forIndexPath:indexPath];
MenuItems *item=[itemsfinal objectAtIndex:indexPath.row];
NSMutableString *str = [NSMutableString stringWithFormat:#"%#", item.itemImage];
NSLog(#" url %#",str);
UIImage *image = [UIImage imageWithContentsOfFile:[self loadImage:str]];
if(image !=nil){
collectionCell.menuRecipeImage.image = image;
collectionCell.activityIndicator.hidden = YES;
[collectionCell.activityIndicator stopAnimating];
}else{
collectionCell.activityIndicator.hidden = NO;
[collectionCell.activityIndicator startAnimating];
collectionCell.menuRecipeImage.image = [UIImage imageNamed:#"menudefualt.png"];
}
return collectionCell;
}
In cellForItemAtIndexPath you should set up your activity indicator. Then start loading your image for the cell in the background. When the image have loaded apply it to the cell on the main thread.
- (UICollectionViewCell *)collectionView:(UICollectionView *)cv cellForItemAtIndexPath:(NSIndexPath *)indexPath {
__block UICollectionViewCell* cell = [cv dequeueReusableCellWithReuseIdentifier:#"cell"
forIndexPath: indexPath];
// Placeholder text --
UILabel* label = [[UILabel alloc] initWithFrame:cell.bounds];
label.text = #"Downloading...";
[cell.contentView addSubview:label];
// Load image in background --
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{
NSURL* url = [NSURL URLWithString: [NSString stringWithFormat:#"http://example.com/img/img%02lu.png", (long unsigned)indexPath.row]];
// Load and decode image --
NSData * imageData = [NSData dataWithContentsOfURL:url];
UIImage *image = [UIImage imageWithData:imageData];
// Apply image on the main thread --
dispatch_sync(dispatch_get_main_queue(), ^{
UIImageView* iv = [[UIImageView alloc] initWithImage:image];
[cell.contentView addSubview:iv];
});
});
return cell;
}
The example in action...
One thing about Niels example is that this may cause an incorrect image to be set for a cell, if the cell is re-used before the image is completely loaded (eg. if you're scrolling quickly). So you need to keep a map of what URL should be set for each cell, so roughly modifying Niels' example above:
#property NSDictionary *cellMap;
- (UICollectionViewCell *)collectionView:(UICollectionView *)cv cellForItemAtIndexPath:(NSIndexPath *)indexPath {
__block UICollectionViewCell* cell = [cv dequeueReusableCellWithReuseIdentifier:#"cell"
forIndexPath: indexPath];
// Placeholder text --
UILabel* label = [[UILabel alloc] initWithFrame:cell.bounds];
label.text = #"Downloading...";
[cell.contentView addSubview:label];
NSURL* url = [NSURL URLWithString: [NSString stringWithFormat:#"http://example.com/img/img%02lu.png", (long unsigned)indexPath.row]];
[cellMap setObject:url forKey:cell];
// Load image in background --
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{
// Load and decode image --
NSData * imageData = [NSData dataWithContentsOfURL:url];
UIImage *image = [UIImage imageWithData:imageData];
// Apply image on the main thread --
dispatch_sync(dispatch_get_main_queue(), ^{
NSURL *cellUrl = [cellMap objectForKey:cell];
if (cellUrl == url) {
// Only set the image if the url is still the same for this cell
UIImageView* iv = [[UIImageView alloc] initWithImage:image];
[cell.contentView addSubview:iv];
}
});
});
return cell;
}
You should use async image load. It can be done with GCD
//First start your activityIndicator
collectionCell.activityIndicator.hidden = NO;
[collectionCell.activityIndicator startAnimating];
//Then using GCD load your image on secondary thread
dispatch_async(dispatch_get_global_queue(0, 0), ^{
//Here your image loading from url
UIImage *image = [UIImage imageWithContentsOfFile:[self loadImage:str]];
dispatch_async(dispatch_get_main_queue(), ^{
//This block (Main thread) waits until your image will be downloaded
//(Note that all operation with views must be executed on a main thread)
//Then loading is done just set your image and stop activityIndicator
collectionCell.menuRecipeImage.image = image;
collectionCell.activityIndicator.hidden = YES;
[collectionCell.activityIndicator stopAnimating];
});
});
- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView{
return 1;
}
- (NSInteger)collectionView:(UICollectionView *)view numberOfItemsInSection:(NSInteger)section{
return _items.count;
}
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath{
ImageFilterCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:#"ImageFilterCell" forIndexPath:indexPath];
cell.lblEffectName.text = [_itemsName objectAtIndex:indexPath.row];
cell.imgLoader.hidden = NO;
cell.imgFilter.image = nil;
NSString *effectName = _items[indexPath.row];
if([effectName isEqualToString:#"Original"]){
cell.imgLoader.hidden = YES;
cell.imgFilter.image = _imgThumb;
}
else {
UIImage *filteredImage = [_filteredImages objectForKey:effectName];
if(filteredImage){
cell.imgLoader.hidden = YES;
cell.imgFilter.image = filteredImage;
} else {
__weak ImageFilterCell *weakCell = cell;
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[self getFilteredImageForEffect:effectName forImage:_imgThumb completionBlock:^(UIImage *image) {
dispatch_async(dispatch_get_main_queue(), ^{
weakCell.imgLoader.hidden = YES;
weakCell.imgFilter.image = image;
[_filteredImages setObject:image forKey:effectName];
});
}];
});
}
}
if(_checkedIndexPath==indexPath.row)
cell.highlighted = YES;
else
cell.highlighted = NO;
return cell;
}
- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath {
if(_checkedIndexPath != indexPath.row && indexPath.row!=0){
_checkedIndexPath = indexPath.row;
NSString *effectName = _items[indexPath.row];
if([_delegate respondsToSelector:#selector(showIndicator)]){
[_delegate showIndicator];
}
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[self getFilteredImageForEffect:effectName forImage:_orgImage completionBlock:^(UIImage *image) {
dispatch_async(dispatch_get_main_queue(), ^{
if([self.delegate respondsToSelector:#selector(filterImageView:filteredImage:)]){
[self.delegate filterImageView:self filteredImage:image];
}
});
}];
});
} else if (indexPath.row == 0) {
_checkedIndexPath = 0;
if([self.delegate respondsToSelector:#selector(filterImageView:filteredImage:)]){
[self.delegate filterImageView:self filteredImage:_orgImage];
}
}
[_collectionView reloadData];
}

a specific instance of insertsubview at index not working in ios 6.0

I'm testing my ios app that has a deployment target of 5.0 and a base SDK of 6.1.
Everything works fine in ios 5.0, and ios 5.1, but in ios 6.0 I'm having an issue with inserting a subview at index. The subview is a tableview and the parent view is an uialertview that was created as a special class "UIAlertTableView." The alertview appears, but there appears to be nothing inserted. Before this, I had fixed an autorotation issue of the superview (which is in landscape) because, as it is well known ios 6.0 handles rotation differently, so now my superview appears correctly, but as I said, this alertview pops up with no table now. Am I suppose to be fixing autorotation issues for the tableview as well as the superview? I didn't think this would be necessary since the tableview is not declared in the imported class, is is declared within the parent viewcontroller. Or could this be because of some method that was deprecated in ios 6.0?
/*UIAlertTableView.m (the imported object class)*/
#interface UIAlertView (private)
- (void)layoutAnimated:(BOOL)fp8;
#end
#implementation UIAlertTableView
#synthesize tableWidth;
#synthesize tableHeight;
#synthesize lowestView;
#synthesize kTablePadding;
#synthesize alertDelegate;
- (void)layoutAnimated:(BOOL)fp8 {
[super layoutAnimated:fp8];
[self setFrame:CGRectMake(self.frame.origin.x, self.frame.origin.y - tableExtHeight/2, self.frame.size.width, self.frame.size.height + tableExtHeight)];
// We get the lowest non-control view (i.e. Labels) so we can place the table view just below
int i = 0;
while (![[self.subviews objectAtIndex:i] isKindOfClass:[UIControl class]]) {
lowestView = [self.subviews objectAtIndex:i];
i++;
}
tableWidth = 262.0f;
for (UIView *sv in self.subviews) {
// Move all Controls down
if ([sv isKindOfClass:[UIControl class]]) {
sv.frame = CGRectMake(sv.frame.origin.x, sv.frame.origin.y + tableExtHeight, sv.frame.size.width, sv.frame.size.height);
}
}
}
- (void)show{
[self prepare];
[super show];
}
- (void)prepare {
if (tableHeight == 0) {
tableHeight = 150.0f;
}
kTablePadding = 8.0f;
tableExtHeight = tableHeight + 2 * kTablePadding;
[self setNeedsLayout];
}
#end
/*the UIAlertTableView class is imported into the myViewController header file*/
/*myViewController.m*/
#implementation myViewController
#synthesize myTableView;
#synthesize alert;
#synthesize imageView;
#synthesize scrollView;
#synthesize models;
#synthesize picked;
#pragma myTableView
-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView{
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return [models count];
}
- (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];
}
// now configure the cell
cell.textLabel.text = [models objectAtIndex:[indexPath row]];
[cell setAccessibilityTraits: UIAccessibilityTraitButton];
return cell;
}
- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath
{
if (returnedSetting && (indexPath.row == prevSelectedIndex)){
returnedSetting = FALSE;
}
}
-(void) prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender{
//index path to row that's selected
NSIndexPath *myIndexPath = [myTableView indexPathForSelectedRow];
UITableViewCell *cell = [myTableView cellForRowAtIndexPath:myIndexPath];
labelText = cell.textLabel.text;
selectedModel = cell.textLabel.text;
}
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
NSIndexPath *myIndexPath = [tableView indexPathForSelectedRow];
prevSelectedIndex = myIndexPath.row;
UITableViewCell *cell = [tableView cellForRowAtIndexPath:myIndexPath];
[alert dismissWithClickedButtonIndex:0 animated:YES];
labelText = cell.textLabel.text;
selectedModel = cell.textLabel.text;
[self dismissModalViewControllerAnimated:YES];
}
-(void)removeButton{
[UIView animateWithDuration:1.5
delay:1.5
options:UIViewAnimationCurveEaseInOut
animations:^ {
eButton.alpha = 0;
}
completion:^(BOOL finished) {
}];
}
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)didReceiveMemoryWarning
{
// Releases the view if it doesn't have a superview.
[super didReceiveMemoryWarning];
// Release any cached data, images, etc that aren't in use.
}
-(void)showAlertFor:(NSTimer *)timer{
[alert show];
myTableView.frame = CGRectMake(11.0f, alert.lowestView.frame.origin.y + alert.lowestView.frame.size.height + 2 * alert.kTablePadding, alert.tableWidth, alert.tableHeight);
[alert insertSubview:myTableView atIndex:1];
[myTableView performSelector:#selector(flashScrollIndicators) withObject:nil afterDelay:.3];
}
-(void)bringupAlertTableViewFor:(NSString *)dName atLocationOnScreen:(CGPoint)newPoint{
if (([dName isEqualToString:#"hello"]){
picked =TRUE;
myTableView = [[UITableView alloc] initWithFrame:CGRectMake(0.0f, 0.0f, 0.0f, 0.0f) style:UITableViewStylePlain];
alert = [[UIAlertTableView alloc] initWithTitle:dName
message:#"Choose from the table below:"
delegate:self
cancelButtonTitle:#"Cancel"
otherButtonTitles:nil];
[alert setDelegate: alert.alertDelegate];
models = [[NSMutableArray alloc]init];
myTableView.delegate = self;
myTableView.dataSource = self;
NSEntityDescription *entitydesc = [NSEntityDescription entityForName:#"Decisions" inManagedObjectContext:context];
NSFetchRequest *request = [[NSFetchRequest alloc]init];
[request setEntity:entitydesc];
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"dName == %#", dName];
[request setPredicate: predicate];
NSError *error;
//matches found
NSArray *matchingData = [context executeFetchRequest: request error: &error];
for (NSManagedObject *obj in matchingData) {
[models addObject:[NSString stringWithFormat:#"%#",[obj valueForKey: #"model"]]];
}
alert.tableHeight = 120;
[alert show];
myTableView.frame = CGRectMake(11.0f, alert.lowestView.frame.origin.y + alert.lowestView.frame.size.height + 2 * alert.kTablePadding, alert.tableWidth, alert.tableHeight);
[alert insertSubview:myTableView atIndex:1];
[myTableView performSelector:#selector(flashScrollIndicators) withObject:nil afterDelay:.3];
}else{
picked = TRUE;
frame.origin.x = newPoint.x - 29; // new x coordinate
frame.origin.y = 240; // new y coordinate
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration: 1.5];
[UIView commitAnimations];
myTableView = [[UITableView alloc] initWithFrame:CGRectMake(0.0f, 0.0f, 0.0f, 0.0f) style:UITableViewStylePlain];
alert = [[UIAlertTableView alloc] initWithTitle:dName
message:#"Select a choice:"
delegate:self
cancelButtonTitle:#"Cancel"
otherButtonTitles:nil];
[alert setDelegate: alert.alertDelegate];
models = [[NSMutableArray alloc]init];
myTableView.delegate = self;
myTableView.dataSource = self;
NSEntityDescription *entitydesc = [NSEntityDescription entityForName:#"Decisions" inManagedObjectContext:context];
NSFetchRequest *request = [[NSFetchRequest alloc]init];
[request setEntity:entitydesc];
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"deName == %#", dName];
[request setPredicate: predicate];
NSError *error;
//matches found
NSArray *matchingData = [context executeFetchRequest: request error: &error];
for (NSManagedObject *obj in matchingData) {
[models addObject:[NSString stringWithFormat:#"%#",[obj valueForKey: #"model"]]];
}
alert.tableHeight = 120;
[NSTimer scheduledTimerWithTimeInterval:1.5 target:self selector:#selector(showAlertFor:) userInfo:nil repeats:NO];
previousPoint = newPoint;
}
}
-(IBAction)singleTapImageView:(UITapGestureRecognizer *)sender {
CGPoint pt = [sender locationInView: sender.view];
//find out which was pressed
if ( ((pt.x >= 52) && (pt.x <= 79)) && ((pt.y >= 269) && (pt.y <= 296))){
CGPoint newPoint = {45, (257 + 55)};
[self bringupAlertTableViewFor:#"Choice1" atLocationOnScreen:newPoint];
}
}
#pragma mark - View lifecycle
// Implement viewDidLoad to do additional setup after loading the view, typically from a nib.
-(void)scrollViewDidEndScrollingAnimation:(UIScrollView *)sView{
[self removeButton];
}
-(void)scrollViewDidScroll:(UIScrollView *)sView{
eButton.alpha = .7;
}
-(void)scrollViewDidEndDecelerating:(UIScrollView *)sView
{
[self removeButton];
}
-(void)exitButtonPressed{
[self dismissModalViewControllerAnimated:YES];
}
- (void)viewDidLoad
{
UIImage *imageS = [UIImage imageNamed:#"ti.png"];
imageView = [[TouchDetectingImageView alloc]initWithImage:imageS];
[imageView setDelegate:self];
imageView.frame = CGRectMake(20, 25, imageS.size.width,imageS.size.height);
CGFloat newScrollWidth = imageView.image.size.width + 20;
[scrollView setContentSize:(CGSizeMake(newScrollWidth, imageView.image.size.height))];
[scrollView addSubview: imageView];
imageView.contentMode = UIViewContentModeScaleToFill;
UITapGestureRecognizer *singleTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(singleTapImageView:)];
singleTap.numberOfTapsRequired = 1;
[scrollView addGestureRecognizer:singleTap];
UIImage *img = [UIImage imageNamed:#"backbutton.png"];
CGRect frameForButton = CGRectMake(0, 3, img.size.width, img.size.height);
eButton = [[exitButton alloc] initWithFrame:frameForButton];
[eButton setDelegate:self];
[eButton addTarget:self action:#selector(exitButtonPressed) forControlEvents:UIControlEventTouchUpInside];
UITapGestureRecognizer *buttonTap = [[UITapGestureRecognizer alloc]initWithTarget:self action:#selector(exitButtonPressed)];
buttonTap.numberOfTapsRequired = 1;
[eButton addGestureRecognizer:buttonTap];
eButton.alpha = 0;
[self.view addSubview:eButton];
[super viewDidLoad];
}
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
}
- (void)viewDidUnload
{
[self setScrollView:nil];
[self setImageView:nil];
[self setmyTableView:nil];
[super viewDidUnload];
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
}
-(void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex{
[scrollView flashScrollIndicators];
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
// The menu is only going to support landscape orientations
return ((interfaceOrientation == UIInterfaceOrientationLandscapeLeft) || (interfaceOrientation == UIInterfaceOrientationLandscapeRight));
}
- (NSInteger)supportedInterfaceOrientations
{
return UIInterfaceOrientationMaskLandscapeLeft | UIInterfaceOrientationMaskLandscapeRight;
}
-(BOOL)shouldAutorotate{
return YES;
}
#end
The reason(s) for this were:
1) the call to layoutAnimated was being ignored
2) it appears that ios 6 handles view hierarchy somewhat differently...
3) ios 6.0 automatically scales to fit a 1136x640 display vs earlier version that scale to fit a 960x640 display.
solutions were:
use a layoutsubviews call and layoutifneeded
also using conditional statements to find the ios version (e.g. greater_than_or_equal_to ios 6.0)

message sent to deallocated instance (probably UITableViewCell)

I know that a lot of folks have had this problem before and I've read a lot of suggested solutions, none of which has worked out for me. I'm working on a part of a larger project, involving three different views: the first view contains a UITableView with custom made cells called WeekdaySelectionWithPopoverCellController. This cell contains a label designating the weekday (Monday through Friday), a UISwitch and the following elements that are displayed or hidden respectively based on the state of the switch. If the switch is on, the cell looks like this:
----------------------------------------------------------------------
| Monday [ON/off] between ( N/A ) and ( N/A ) |
----------------------------------------------------------------------
If it's off it looks like this:
----------------------------------------------------------------------
| Monday [on/OFF] |
----------------------------------------------------------------------
The (N/A) elements are UIButtons. If the user hits one of those buttons a UIPopover with a date picker opens. The idea is that the user selects a time from the picker that should be displayed on the UIButtons instead of the (N/A):
----------------------------------------------------------------------
| Monday [ON/off] between ( 12:30 ) and ( 16:00 ) |
----------------------------------------------------------------------
The hiding of the elements on hitting the UISwitch works as does the display of the popover. However, if the user hits the "Done" button in the popover and the popover is dismissed the app crashes with the following error:
-[UITableViewCell isKindOfClass:]: message sent to deallocated instance 0xf42a100
Strangely enough the only place containing code that calls isKindOfClass is ModalTableViewController (the parent view of the popover and the custom cells) and the address of the instance displayed does not belong to it. Neither is it the address of the popover which only leaves the class of the custom cells (WeekdaySelectionWithPopoverCellController).
Let me give you the relevant parts of the ModalTableViewController.m:
#implementation ModalTableViewController
#synthesize mtvcNavigationBar;
#synthesize mtvcTableView;
#synthesize cell;
#synthesize lable;
#synthesize button;
// WeekdaySelectionWithPopoverCell
#synthesize wswpMainLabel;
#synthesize wswpFromLabel;
#synthesize wswpToLabel;
#synthesize wswpOClockFromLabel;
#synthesize wswpOClockToLabel;
#synthesize wswpSwitch;
#synthesize wswpFromValueButton;
#synthesize wswpToValueButton;
#synthesize popoverController;
// more code...
- (ModalTableViewController *)initWithParam:(NSString *)title andData:(NSArray *)myData andSelection:(NSArray *)selection {
[self initSwipeLeftNavigation];
mtvcNavigationBar.topItem.title = title;
mtvcSectionSize = [myData count];
mtvcSectionname = #"";
mtvcLabels = myData;
mtvcData = selection;
[mtvcLabels retain];
[mtvcData retain];
[otherValues retain];
mtvSingleton = [ModalTableViewSingleton sharedInstance];
return self;
}
// more code...
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cellRet;
NSString *MyIdentifier = #"WeekdaySelectionWithPopoverCellController";
cellRet = [tableView dequeueReusableCellWithIdentifier:MyIdentifier];
if (cellRet == nil) {
[[NSBundle mainBundle] loadNibNamed:MyIdentifier owner:self options:nil];
cellRet = self.cell;
}
NSDictionary *tempValues;
tempValues = [mtvcData objectAtIndex:indexPath.row];
wswpSwitch = (UISwitch *)[cellRet viewWithTag:2];
wswpSwitch.on = [[tempValues valueForKey:#"company_id"] isKindOfClass:[NSNull class]] ? false: true;
BOOL negatedState = !wswpSwitch.on;
NSLog(#"tempValues: %#", tempValues);
lable = (UILabel *)[cellRet viewWithTag:1];
lable.text = [NSString stringWithFormat:#"%#", [tempValues valueForKey:#"short"]];
lable.font = [UIFont boldSystemFontOfSize:16];
lable = (UILabel *)[cellRet viewWithTag:3];
lable.font = [UIFont boldSystemFontOfSize:16];
lable.text = [NSString stringWithFormat:#"%#", #"von"];
lable.hidden = negatedState;
lable = (UILabel *)[cellRet viewWithTag:5];
lable.text = [NSString stringWithFormat:#"%#", #"bis"];
lable.font = [UIFont boldSystemFontOfSize:16];
lable.hidden = negatedState;
lable = (UILabel *)[cellRet viewWithTag:7];
lable.text = #"Uhr";
lable.font = [UIFont boldSystemFontOfSize:16];
lable.hidden = negatedState;
lable = (UILabel *)[cellRet viewWithTag:8];
lable.text = #"Uhr";
lable.font = [UIFont boldSystemFontOfSize:16];
lable.hidden = negatedState;
button = (UIButton *)[cellRet viewWithTag:4];
[self setButtonLabel:button forKey:#"beginning" fromDict:tempValues];
button.hidden = negatedState;
/*
if (![[tempValues valueForKey:#"beginning"] isKindOfClass:[NSNull class]]) {
button.titleLabel.text = [NSString stringWithFormat:#"%#", [tempValues valueForKey:#"beginning"]];
} else {
button.titleLabel.text = #"k.A.";
}
*/
button = (UIButton *)[cellRet viewWithTag:6];
[self setButtonLabel:button forKey:#"until" fromDict:tempValues];
button.hidden = negatedState;
/*
if (![[tempValues valueForKey:#"until"] isKindOfClass:[NSNull class]]) {
button.titleLabel.text = [NSString stringWithFormat:#"%#", [tempValues valueForKey:#"until"]];
} else {
button.titleLabel.text = #"k.A.";
}
*/
self.cell = nil;
return cellRet;
}
- (void)setButtonLabel:(UIButton *)btn forKey:(NSString *)key fromDict:(NSDictionary *)dict {
[btn setTitleColor:[UIColor blueColor] forState:UIControlStateNormal];
NSString *text = [dict objectForKey:key];
if ([mtvSingleton.sharedData objectForKey:key]) {
[btn setTitle:[mtvSingleton.sharedData objectForKey:key] forState:UIControlStateNormal];
} else {
if ([text isKindOfClass:[NSNull class]] ||
[text isEqualToString:#""])
{
[btn setTitle:#"k.A." forState:UIControlStateNormal];
} else {
[btn setTitle:text forState:UIControlStateNormal];
}
}
}
// more code...
- (IBAction)switchButtonValueChanged:(id)sender
{
//[self changeDisplayState:wsdSwitch.on forObj:sender];
// UISwitch *tmp = (UISwitch *)sender;
UIView *v = (UIView *)sender;
do {
v = v.superview;
} while (![v isKindOfClass:[UITableViewCell class]]);
// WeekdaySelectionWithPopoverCellController *cell1 = (WeekdaySelectionWithPopoverCellController *)v;
cell = (UITableViewCell *)v;
wswpSwitch = (UISwitch *)[cell viewWithTag:2];
BOOL negatedState = !wswpSwitch.on;
lable = (UILabel *)[cell viewWithTag:3];
lable.hidden = negatedState;
lable = (UILabel *)[cell viewWithTag:5];
lable.hidden = negatedState;
lable = (UILabel *)[cell viewWithTag:7];
lable.hidden = negatedState;
lable = (UILabel *)[cell viewWithTag:8];
lable.hidden = negatedState;
button = (UIButton *)[cell viewWithTag:4];
button.hidden = negatedState;
button = (UIButton *)[cell viewWithTag:6];
button.hidden = negatedState;
/*
wswpSwitch = (UISwitch *)[cell1 viewWithTag:2];
BOOL negatedState = !wswpSwitch.on;
lable = (UILabel *)[cell1 viewWithTag:3];
lable.hidden = negatedState;
lable = (UILabel *)[cell1 viewWithTag:5];
lable.hidden = negatedState;
lable = (UILabel *)[cell1 viewWithTag:7];
lable.hidden = negatedState;
lable = (UILabel *)[cell1 viewWithTag:8];
lable.hidden = negatedState;
button = (UIButton *)[cell1 viewWithTag:4];
button.hidden = negatedState;
button = (UIButton *)[cell1 viewWithTag:6];
button.hidden = negatedState;
*/
}
#pragma mark - handlers
- (IBAction)toButtonHandler:(id)sender {
dppvc = [[DatePickerPopoverViewController alloc] initWithCaller:self andKey:#"beginning"];
UIPopoverController *popover = [[UIPopoverController alloc] initWithContentViewController:dppvc];
popover.delegate = self;
self.popoverController = popover;
[popover release];
[self.popoverController presentPopoverFromRect:[(UIButton *)sender frame]
inView:self.view
permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES];
}
- (IBAction)fromButtonHandler:(id)sender {
dppvc = [[DatePickerPopoverViewController alloc] initWithCaller:self andKey:#"until"];
UIPopoverController *popover = [[UIPopoverController alloc] initWithContentViewController:dppvc];
popover.delegate = self;
self.popoverController = popover;
[popover release];
CGRect senderFrameRect = [(UIButton *)sender frame];
[self.popoverController presentPopoverFromRect:senderFrameRect
inView:self.view
permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES];
}
#pragma mark - UIPopoverControllerDelegate
//---called when the user clicks outside the popover view---
- (BOOL)popoverControllerShouldDismissPopover:(UIPopoverController *)popoverController {
// NSLog(#"popover about to be dismissed");
return YES;
}
//---called when the popover view is dismissed---
- (void)popoverControllerDidDismissPopover:(UIPopoverController *)popoverController {
// NSLog(#"popover dismissed");
}
- (void)dismissPopover {
if (popoverController != nil) {
[popoverController dismissPopoverAnimated:YES];
NSMutableArray *indexPaths = [[NSMutableArray alloc] init];
int i;
for (i = 0; i < [mtvcLabels count]; i++) {
[indexPaths addObject:[NSIndexPath indexPathForRow:i inSection:0]];
}
[mtvcTableView reloadRowsAtIndexPaths:indexPaths withRowAnimation:YES];
}
}
- (void)dealloc {
[mtvcSectionname release];
[mtvcLabels release];
[mtvcData release];
[cell release];
[super dealloc];
}
The crash occurs in main.m:
int main(int argc, char *argv[])
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
// crashes:
int retVal = UIApplicationMain(argc, argv, nil, nil); // <--
[pool release];
return retVal;
}
I have enabled NSZombieEnabled, MallocStackLoggingNoComp and NSAutoreleaseFreedObjectCheckEnabled but the compiler doesn't give me any more information than what I posted.
I've spent the entire day trying to resolve this but to no avail. Any hint in the right direction is appreciated!
I've been able to take care of this particular error. The problem was that cellRet in cellForRowAtIndexPath had not been retained. The following snippet resolves the error mentioned above:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cellRet;
NSString *MyIdentifier = #"WeekdaySelectionWithPopoverCellController";
cellRet = [tableView dequeueReusableCellWithIdentifier:MyIdentifier];
if (cellRet == nil) {
[[NSBundle mainBundle] loadNibNamed:MyIdentifier owner:self options:nil];
cellRet = self.cell;
[cellRet retain];
}
// ...
}
Now however, I'm stuck with a new, similar error. This time it says:
*** -[CALayer release]: message sent to deallocated instance 0xc656d30
The following topic has some more information on the problem: "[CALayer release]: message sent to deallocated instance" when dismissing modal view controller
I have tried to change the property of the popover view controller to assign instead of retain but that gave me the message sent to deallocated instance error again, this time for the popover view controller.
Somebody with an idea? TIA!
The way I usually handle this is to create a subclass of UITableViewCell for my custom cells. and use the nib. I create a custom init that loads the cell from the nib. as follows.
- (id)init
{
self = [[[[NSBundle mainBundle] loadNibNamed:#"NibName" owner:self options:nil] objectAtIndex:0] retain];
if (self)
{
// any further initialization
}
return self;
}
in the nib set the cell's class to your new class.
then to use your cell do the following.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"CustomCell";
CustomCell *cell = (CustomCell *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (!cell)
{
cell = [[[CustomCell alloc] init] autorelease];
}
// setup your cell
return cell;
}
You should definitely be using assign on your delegate properties.

Section headerview in UITableView Duplicated

I am creating an application and I have a customized header of tableview. But sometimes the header gets duplicated. It takes the place of a row in tableview. How do I solve this strange problem? BTW, my tableviewstyle is plain, Header height is 44.0 and the footer height is 0.0. Here is an image how it displays. The header "comments" is duplicated just below the header "Messages" while it should be the row.
Here is the complete implementation of this view
// Implement viewDidLoad to do additional setup after loading the view, typically from a nib.
- (void)viewDidLoad {
[super viewDidLoad];
TitleForSectionView=[[NSArray arrayWithObjects:#"Dates To Remember",#"Messages",#"Comments",#"Wishlist",#"Reminders",#"Bookmarks",nil] retain];
self.MySectionIndexArray=[[NSMutableArray alloc] init];
[self.MySectionIndexArray addObject:#"UP"];
[self.MySectionIndexArray addObject:#"DOWN"];
[self.MySectionIndexArray addObject:#"DOWN"];
[self.MySectionIndexArray addObject:#"DOWN"];
[self.MySectionIndexArray addObject:#"DOWN"];
[self.MySectionIndexArray addObject:#"DOWN"];
self.IconsForSectionsView=[[NSMutableArray alloc] init];
[self.IconsForSectionsView addObject:[UIImage imageNamed:#"IconCalender.png"]];
[self.IconsForSectionsView addObject:[UIImage imageNamed:#"IconMessage.png"]];
[self.IconsForSectionsView addObject:[UIImage imageNamed:#"IconComments.png"]];
[self.IconsForSectionsView addObject:[UIImage imageNamed:#"IconWishList.png"]];
[self.IconsForSectionsView addObject:[UIImage imageNamed:#"IconReminder.png"]];
[self.IconsForSectionsView addObject:[UIImage imageNamed:#"IconBookMark.png"]];
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 6;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
if ([[self.MySectionIndexArray objectAtIndex:section] isEqualToString:#"UP"]) {
return 4;
} else {
return 0;
}
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *MyDashBoardCell=nil;
static NSString *AddNewDateCellIdentifier=#"AddNewDateCell";
static NSString *CellIdentifier = #"DashBoardCell";
DashBoardCustomCellObject = (DashBoardCustomCell *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (DashBoardCustomCellObject == nil) {
[[[[NSBundle mainBundle] loadNibNamed:#"DashBoardCustomCell" owner:self options:nil] retain]autorelease];
}
[DashBoardCustomCellObject SetDashBoardCellData:#"Mar 9" EventText:#"My Birthday"];
AddNewDateCellObject = (AddNewDateCell *)[tableView dequeueReusableCellWithIdentifier:AddNewDateCellIdentifier];
if (AddNewDateCellObject == nil) {
[[[[NSBundle mainBundle] loadNibNamed:#"AddNewDateCell" owner:self options:nil] retain]autorelease];
}
if(indexPath.section==0 && indexPath.row==0)
{
MyDashBoardCell=AddNewDateCellObject;
}
else
{
MyDashBoardCell=DashBoardCustomCellObject;
}
return MyDashBoardCell;
}
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
{
// create the parent view that will hold header Label and button and icon image
self.customView = [[[UIView alloc] initWithFrame:CGRectMake(0,0,tableView.bounds.size.width,44)] autorelease];
self.customView.backgroundColor=[UIColor whiteColor];
// create image object
UIImageView *icon= [[[UIImageView alloc] initWithImage:[self.IconsForSectionsView objectAtIndex:section]] autorelease];
icon.contentMode=UIViewContentModeCenter;
icon.frame = CGRectMake(0,0,40,40);
// create the label objects
UILabel *headerLabel = [[[UILabel alloc] initWithFrame:CGRectZero] autorelease];
headerLabel.backgroundColor = [UIColor clearColor];
headerLabel.font = [UIFont boldSystemFontOfSize:13];
headerLabel.frame = CGRectMake(53,11,172,21);
headerLabel.text = [TitleForSectionView objectAtIndex:section];
headerLabel.textColor = [UIColor blackColor];
headerLabel.highlightedTextColor=[UIColor whiteColor];
// create the button objects
ButtonDrop = [[[UIButton alloc] initWithFrame:CGRectMake(278, 9, 25, 25)] autorelease];
ButtonDrop.tag=section;
if ([[self.MySectionIndexArray objectAtIndex:section] isEqualToString:#"UP"])
{
[ButtonDrop setBackgroundImage:[UIImage imageNamed:#"Up.png"] forState:UIControlStateNormal];
self.customView.backgroundColor=[UIColor blueColor];
headerLabel.highlighted=YES;
}
else
{
[ButtonDrop setBackgroundImage:[UIImage imageNamed:#"Down.png"] forState:UIControlStateNormal];
}
[ButtonDrop addTarget:self action:#selector(checkAction:) forControlEvents:UIControlEventTouchUpInside];
[self.customView addSubview:icon];
[self.customView addSubview:headerLabel];
[self.customView addSubview:ButtonDrop];
return self.customView;
}
- (void)checkAction:(id)sender
{
UIButton *Button = (UIButton*)sender;
NSLog(#"Button Tag=%d",Button.tag);
if([[self.MySectionIndexArray objectAtIndex:Button.tag] isEqualToString:#"UP"])
{
[self.MySectionIndexArray replaceObjectAtIndex:Button.tag withObject:#"DOWN"];
[ButtonDrop setBackgroundImage:[UIImage imageNamed:#"Up.png"] forState:UIControlStateNormal];
}
else
{
[self.MySectionIndexArray replaceObjectAtIndex:Button.tag withObject:#"UP"];
[ButtonDrop setBackgroundImage:[UIImage imageNamed:#"Down.png"] forState:UIControlStateNormal];
}
[TableDashBoard reloadSections:[NSIndexSet indexSetWithIndex:Button.tag] withRowAnimation:UITableViewRowAnimationFade];
}
Try having a zero-height row for your empty sections. That seems to make them draw correctly for me.
I think there are a couple of explainations:
(1) You're displaying the section header of an empty section which would cause two headers to appear one on top of the other with no rows in between.
(2) You are returning a header view as a row cell in – tableView:cellForRowAtIndexPath: Since the header "it takes place of a row in tableview" I think this the most likely explanation. Check – tableView:viewForHeaderInSection: as well.