UITableView with Json file, loading images to cell disappear - ios

I am using asyncimageview classes nicely provided by: http://www.markj.net/iphone-asynchronous-table-image/
I am getting image urls from a json file and loading each image to a cell.
Problem:
When i scroll up, and scroll back down to the same cell, the image reloads (disappears and appears again). I can't figure out why the image keeps reloading? Does anyone have suggestions or a solution to how I could make it stop? Thanks in advance!
// Asks the data source to return a cell to insert in a particular table view location
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
//Gets the current news article
NewsArticle *theCurrentArticle = [self.listofNewsArticles objectAtIndex:[indexPath row]];
//Gets the title from the current article
NSString *theTitle = theCurrentArticle.title;
//Gets the image url
NSString *imageUrl = theCurrentArticle.imageURL;
//Gets the description of the current news article
NSString *theDescription = theCurrentArticle.description;
NewsCustomCell *cell = (NewsCustomCell *)[tableView dequeueReusableCellWithIdentifier:#"NewsContent"];
__block NewsCustomCell *aCell;
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
if (cell == nil) {
aCell = (NewsCustomCell *)[tableView dequeueReusableCellWithIdentifier:#"NewsContent"];
} else {
AsyncImageView* oldImage = (AsyncImageView*)
[cell.contentView viewWithTag:999];
[oldImage removeFromSuperview];
}
AsyncImageView *imageView = [[AsyncImageView alloc] initWithFrame:CGRectMake(5, 5, 100, 100)];
imageView.tag = 999;
dispatch_async(dispatch_get_main_queue(), ^{
[imageView loadImageFromURL:[NSURL URLWithString:imageUrl]];
[cell.contentView addSubview:imageView];
cell.titleLabel.text = theTitle;
cell.descriptionLabel.text = theDescription;
cell.imageLabel.contentMode = UIViewContentModeScaleAspectFill;
});
});
return cell;
}
Heres what the current app looks like:
Solution:
Just worked with this class I finally found.
https://github.com/rs/SDWebImage
This handles caching, async downloads. Wish I found this sooner..

I hope you have Write AsyncImageView and ImageCache and ImageCacheObject classes.
Write this code inside cellForRowAtIndexPath:
static NSString *CellIdentifier = #"CellIdentifier";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil)
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
Quest_Forum *Quest_ForumObj=[queArr objectAtIndex:i+indexPath.row];
// NSLog(#"cell for row at... i val.. %d",i+indexPath.row);
for(UIView * view in cell.contentView.subviews){
if([view isKindOfClass:[AsyncImageView class]])
{
// NSLog(#"remove old images");
[view removeFromSuperview];
view = nil;
}
}
AsyncImageView *asyncImageView = nil;
UIImageView *cellImage = (UIImageView *)[cell viewWithTag:1]; // Inside tableview i have taken tableviewcell and given tag 1 to that imageview
asyncImageView = [[AsyncImageView alloc] initWithFrame:cellImage.frame] ;
[asyncImageView loadImageFromURL:Quest_ForumObj.Quest_Image];
asyncImageView.backgroundColor=[UIColor clearColor];
[cell.contentView addSubview:asyncImageView];
UILabel *lblQuest = (UILabel *)[cell viewWithTag:2]; // Given tag 2 to the label inside tableViewCell
lblQuest.text=Quest_ForumObj.Question;
In ImageCacheObject.h
#class ImageCacheObject;
#interface ImageCache : NSObject
{
NSUInteger totalSize; // total number of bytes
NSUInteger maxSize; // maximum capacity
NSMutableDictionary *myDictionary;
}
#property (nonatomic, readonly) NSUInteger totalSize;
-(id)initWithMaxSize:(NSUInteger) max;
-(void)insertImage:(UIImage*)image withSize:(NSUInteger)sz forKey:(NSString*)key;
-(UIImage*)imageForKey:(NSString*)key;
In ImageCacheObject.m
#import "ImageCacheObject.h"
#synthesize totalSize;
-(id)initWithMaxSize:(NSUInteger) max
{
if (self = [super init])
{
totalSize = 0;
maxSize = max;
myDictionary = [[NSMutableDictionary alloc] init];
}
return self;
}
-(void)dealloc // Don't write this method if you are using ARC
{
[myDictionary release];
[super dealloc];
}
-(void)insertImage:(UIImage*)image withSize:(NSUInteger)sz forKey:(NSString*)key
{
// NSLog(#"count of insert image%d",sz);
ImageCacheObject *object = [[ImageCacheObject alloc] initWithSize:sz Image:image];
while (totalSize + sz > maxSize)
{
NSDate *oldestTime;
NSString *oldestKey;
for (NSString *key in [myDictionary allKeys])
{
ImageCacheObject *obj = [myDictionary objectForKey:key];
if (oldestTime == nil || [obj.timeStamp compare:oldestTime] == NSOrderedAscending)
{
oldestTime = obj.timeStamp;
oldestKey = key;
}
}
if (oldestKey == nil)
break; // shoudn't happen
ImageCacheObject *obj = [myDictionary objectForKey:oldestKey];
totalSize -= obj.size;
[myDictionary removeObjectForKey:oldestKey];
}
[myDictionary setObject:object forKey:key];
[object release];
}
-(UIImage*)imageForKey:(NSString*)key
{
ImageCacheObject *object = [myDictionary objectForKey:key];
if (object == nil)
return nil;
[object resetTimeStamp];
return object.image;
}
In ImageCacheObject.h
#interface ImageCacheObject : NSObject
{
NSUInteger size; // size in bytes of image data
NSDate *timeStamp; // time of last access
UIImage *image; // cached image
}
#property (nonatomic, readonly) NSUInteger size;
#property (nonatomic, retain, readonly) NSDate *timeStamp;
#property (nonatomic, retain, readonly) UIImage *image;
-(id)initWithSize:(NSUInteger)sz Image:(UIImage*)anImage;
-(void)resetTimeStamp;
In ImageCacheObject.m
#synthesize size;
#synthesize timeStamp;
#synthesize image;
-(id)initWithSize:(NSUInteger)sz Image:(UIImage*)anImage
{
if (self = [super init])
{
size = sz;
timeStamp = [[NSDate date] retain];
image = [anImage retain];
}
return self;
}
-(void)resetTimeStamp
{
[timeStamp release];
timeStamp = [[NSDate date] retain];
}
-(void) dealloc
{
[timeStamp release];
[image release];
[super dealloc];
}

Related

UISlider Value Automatically assigned while scrolling in UITable View Cell

I am Working on a Program which looks like this:
There is a Table View i that there is a Custom Table View Cell.
And there is a UISlider , Label and Button on Custom View Cell
Now the Problem is when i slide the UISlider of Cell : 0 than the UISlider at Cell : 12(or later Cell) is Automatically assigned the Cell:0's UISlider Value(Thanks To ARC..!!).
Now anyone have a solution so that the later cell's UISlider doest change while i change value of upper Cells.
P.S. When i assigned a UiSlider Value at Cell:0 and Scroll Up and Down it is automatically random Cell's UISlider Value is changing.
Google Drive Link of Project :
Slider Program
I am Using xCode 5 and iOS SDK 7.
Thanks for Reading.
Edit:
cellForRowAtIndexPath Method
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
static NSString *simpleTableCell = #"Cell";
CustomeTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:simpleTableCell];
if (cell == nil) {
cell = [[CustomeTableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:simpleTableCell];
}
NSString *strName = [NSString stringWithFormat:#"Cell : %d",indexPath.row];
// NSLog(#"strName :%# , SliderValue : %d",strName , (int)cell.mySlider.value);
for (int i = 0; i < arrSlider.count; i++) {
NSString *strTag = [NSString stringWithFormat:#"%#",[[arrSlider objectAtIndex:i]valueForKey:#"tag"]];
NSString *myIndexPath = [NSString stringWithFormat:#"%d",indexPath.row];
if([strTag isEqualToString:myIndexPath])
{
NSString *strValue = [NSString stringWithFormat:#"%#",[[arrSlider objectAtIndex:i]valueForKey:#"value"]];
cell.mySlider.value = [strValue floatValue];
NSLog(#"Tag Value : %# , value %f", strTag , [strValue floatValue]);
}
}
[cell.btnCell setTitle:strName forState:UIControlStateNormal];
cell.btnCell.tag = indexPath.row;
cell.mySlider.tag = indexPath.row;
[cell.mySlider addTarget:self action:#selector(customSliderValue:) forControlEvents:UIControlEventValueChanged];
[cell.btnCell addTarget:self action:#selector(customeBtnClicked:) forControlEvents:UIControlEventTouchDown];
return cell;
}
Use NSMutableDictionary to hold the values of slider then update it from the cellForRowAtIndexPath method i am posting the changes just make changes in your project
in ViewCOntroller.h file
#import <UIKit/UIKit.h>
#import "CustomeTableViewCell.h"
#interface ViewController : UIViewController <UITableViewDataSource ,UITableViewDelegate,SliderDelegate>//confirms to delegate
{
//NSArray *tableList;
UITableView *mytableview;
NSInteger SliderChangeValue;
}
#property (strong , nonatomic) IBOutlet UIView *tableDemo;
#property (strong , nonatomic) NSMutableArray *arrSlider;
#property (strong, nonatomic) NSMutableDictionary *sliderDicValues; //add a mutable dictionary
#property (weak, nonatomic) IBOutlet UITableView *myTableView;//add outlet to tableview
#end
in ViewController.mfile
#import "ViewController.h"
#interface ViewController ()
#end
#implementation ViewController
#synthesize arrSlider;
#synthesize sliderDicValues;
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
// tableList = [NSArray arrayWithObjects:
// #"Cell 1",#"Cell 2",#"Cell 3",#"Cell 4",#"Cell 5",
// #"Cell 6",#"Cell 7",#"Cell 8",#"Cell 9",#"Cell 10",
// #"Cell 11",#"Cell 12",#"Cell 13",#"Cell 14",#"Cell 15",
// #"Cell 16",#"Cell 17",#"Cell 18",#"Cell 19",#"Cell 20",
// nil];
arrSlider = [[NSMutableArray alloc]init];
sliderDicValues = [[NSMutableDictionary alloc]init]; //initilise an mutable dictionary
//[mytableview registerClass:[CustomeTableViewCell class] forCellReuseIdentifier:#"Cell"];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
//[tableList count]
return 15;
}
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *simpleTableCell = #"Cell";
CustomeTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:simpleTableCell];
if (cell == nil) {
cell = [[CustomeTableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:simpleTableCell];
}
if([self.sliderDicValues objectForKey:[NSString stringWithFormat:#"%d",indexPath.row]]) //check if there is any slided value is present
{
NSNumber *value = [self.sliderDicValues objectForKey:[NSString stringWithFormat:#"%d",indexPath.row]];
[cell.mySlider setValue:value.integerValue]; //set the slider value
[cell.myCellLabel setText:[NSString stringWithFormat:#"%d",value.integerValue]];//and also label
}
else //set to default values
{
[cell.mySlider setValue:(NSInteger)0];
[cell.myCellLabel setText:#"label"];
}
//add a single target don't add double target to slider
cell.sliderDelegate = self;//set the delegate
return cell;
/*
NSString *strName = [NSString stringWithFormat:#"Cell : %d",indexPath.row];
NSLog(#"strName :%# , SliderValue : %d",strName , (int)cell.mySlider.value);
for (int i = 0; i < arrSlider.count; i++) {
NSString *strTag = [NSString stringWithFormat:#"%#",[[arrSlider objectAtIndex:i]valueForKey:#"tag"]];
NSString *myIndexPath = [NSString stringWithFormat:#"%d",indexPath.row];
if([strTag isEqualToString:myIndexPath])
{
NSString *strValue = [NSString stringWithFormat:#"%#",[[arrSlider objectAtIndex:i]valueForKey:#"value"]];
cell.mySlider.value = [strValue floatValue];
NSLog(#"Tag Value : %# , value %f", strTag , [strValue floatValue]);
}
if ([strTag isEqual:myIndexPath]) {
//NSString *strValue = [NSString stringWithFormat:#"%#",[[arrSlider objectAtIndex:i]objectForKey:#"value"]];
//NSLog(#"%#",strValue);
NSLog(#"Hello");
//cell.mySlider.value =
}
}
[cell.btnCell setTitle:strName forState:UIControlStateNormal];
cell.btnCell.tag = indexPath.row;
cell.mySlider.tag = indexPath.row;
[cell.mySlider addTarget:self action:#selector(customSliderValue:) forControlEvents:UIControlEventValueChanged];
[cell.btnCell addTarget:self action:#selector(customeBtnClicked:) forControlEvents:UIControlEventTouchDown];
*/
}
//delegate method called from custom cell
- (void)sliderChanged:(CustomeTableViewCell *)cell
{
NSIndexPath *path = [_myTableView indexPathForCell:cell]; //get the indexpath
if(path)//check if valid path
{
SliderChangeValue = cell.mySlider.value;
[self.sliderDicValues setObject:[NSNumber numberWithInt:SliderChangeValue] forKey:[NSString stringWithFormat:#"%d",path.row]]; //set the value in the dictionary later used in the cellForRowAtIndexPath method
}
// SliderChangeValue = (int)sender.value;
NSLog(#"%d",SliderChangeValue);
}
//dont use it
-(void)customSliderValue:(UISlider *)sender{
// NSString *value =[NSString stringWithFormat:#"%d" ,(int)sender.value];
// NSString *tag = [NSString stringWithFormat:#"%d", (int)sender.tag];
//
// NSLog(#"%# %#",value , tag);
//
// [self.dicSilder setObject:value forKey:#"value"];
// [self.dicSilder setObject:tag forKey:#"tag"];
//
// [self.arrSlider addObject:self.dicSilder];
// NSLog(#"%#",self.arrSlider);
SliderChangeValue = (int)sender.value;
NSLog(#"%d",SliderChangeValue);
}
//this is also put a delegate from the cell like slider , just add the another method in the protocol and perform action, if u don't get just comment i will update the code and u hav t modify this method according to your requirement
-(void)customeBtnClicked:(UIButton *)sender
{
NSString *value =[NSString stringWithFormat:#"%d" ,SliderChangeValue];
NSString *tag = [NSString stringWithFormat:#"%d", sender.tag];
//NSLog(#"%# %#",value,tag);
NSMutableDictionary *dic = [[NSMutableDictionary alloc]init];
[dic setObject:value forKey:#"value"];
[dic setObject:tag forKey:#"tag"];
//NSLog(#"%#",dic);
[arrSlider addObject:dic];
NSLog(#"%#",arrSlider);
NSString *sliderTagAtIndexPath = #"";
//NSString *sliderValueAtindexPath = #"";
for (int i = 0; i < arrSlider.count; i++) {
NSString *strTag = [NSString stringWithFormat:#"%#",[[arrSlider objectAtIndex:i]valueForKey:#"tag"]];
if([strTag isEqualToString:tag])
{
//NSString *strValue = [NSString stringWithFormat:#"%#",[[arrSlider objectAtIndex:i]valueForKey:#"value"]];
sliderTagAtIndexPath = strTag;
//sliderValueAtindexPath = strValue;
}
}
UIAlertView *myAlertView = [[UIAlertView alloc]initWithTitle:#"Clicked"
message:[NSString stringWithFormat:#"Cell : %# Value: %d", sliderTagAtIndexPath ,SliderChangeValue]
//message:[NSString stringWithFormat:#"Cell : %# Value: %#", sliderTagAtIndexPath ,sliderValueAtindexPath]
delegate:self
cancelButtonTitle:#"OK"
otherButtonTitles:nil];
[myAlertView show];
}
#end
in CustomeTableViewCell.h file
#import <UIKit/UIKit.h>
//add a custom delegate
#protocol SliderDelegate<NSObject>
- (void)sliderChanged:(id)self;
#end
#interface CustomeTableViewCell : UITableViewCell
#property (weak, nonatomic) IBOutlet UILabel *myCellLabel;
#property (weak, nonatomic) IBOutlet UISlider *mySlider;
#property (weak, nonatomic) IBOutlet UIButton *btnCell;
#property (weak, nonatomic) id <SliderDelegate>sliderDelegate;
- (IBAction)sliderValuechanged:(UISlider *)sender;
#end
in CustomeTableViewCell.m file
#import "CustomeTableViewCell.h"
#implementation CustomeTableViewCell
- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
if (self) {
// Initialization code
}
return self;
}
- (void)awakeFromNib
{
// Initialization code
}
- (void)setSelected:(BOOL)selected animated:(BOOL)animated
{
[super setSelected:selected animated:animated];
// Configure the view for the selected state
}
- (IBAction)sliderValuechanged:(UISlider *)sender
{
self.myCellLabel.text = [NSString stringWithFormat:#"%d",(NSInteger)sender.value];
//call the custom delegate each time when slider is slided
if([_sliderDelegate respondsToSelector:#selector(sliderChanged:)])
{
[_sliderDelegate sliderChanged:self]; //passing the entire cell itself
}
}
#end
Hope this helps u .. :)
You don't need to check(set) all the datasource for a Cell , I mean, No need of for loop inside the cellForRowAtIndexPath. just remove it and will work fine .
Try this code it works for me :
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSString *identifier = [NSString stringWithFormat:#"%d",indexPath.row];
CustomeTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:identifier];
if (!cell) {
cell = [[CustomeTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:identifier];
}
// Write your rest code here
return cell;
}

How to populate a UITableView in a UIView without cellForRowAtIndexPath

I'am dealing with a problem the past few days. I have a UIScrollView in a xib file, in this UIScrollView i put UIViews (as xib too), and in them UIViews i put UITableViews (as xib too). But as a rookie i always populated my UITableView using cellForRowAtindexPath, you return the cell with your wanted text and it's all done, but this time it is not called, so maybe there is another way to populate it ?. As information i'am trying to use CollapseClick as my view. If someone could help me please or have the slightest idea about how to populate it feel free to answer please.
here is my code, i spare you all the xml parsing process.
.m were i init my UITableView
- (void)viewDidLoad
{
[super viewDidLoad];
newsTable = [[UITableView alloc] initWithFrame:[[UIScreen mainScreen] bounds] style:UITableViewCellStyleDefault];
newsTable.delegate = self;
//newsTable.dataSource = self;
myCollapseClick.CollapseClickDelegate = self;
[myCollapseClick reloadCollapseClick];
// If you want a cell open on load, run this method:
[myCollapseClick openCollapseClickCellAtIndex:0 animated:YES];
/*
// If you'd like multiple cells open on load, create an NSArray of NSNumbers
// with each NSNumber corresponding to the index you'd like to open.
// - This will open Cells at indexes 0,2 automatically
NSArray *indexArray = #[[NSNumber numberWithInt:0],[NSNumber numberWithInt:2]];
[myCollapseClick openCollapseClickCellsWithIndexes:indexArray animated:NO];
*/
}
were i need to return the UIViews with the UITable views
-(UIView *)viewForCollapseClickContentViewAtIndex:(int)index {
switch (index) {
case 0:
return test1View;
break;
case 1:
return test2View;
break;
case 2:
return test3View;
break;
default:
return test1View;
break;
}
}
the good old cellForRowAtIndexPath
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *MyIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:MyIdentifier];
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:MyIdentifier];
CGRect frame = CGRectMake(0, 0, 300, 50);
UILabel *lbl1 = [[UILabel alloc] initWithFrame:frame];
lbl1.textAlignment = NSTextAlignmentCenter;
[lbl1 setFont:[UIFont fontWithName:#"Helvetica" size:12.0]];
//self.tableView.separatorColor = [UIColor whiteColor];
//lbl1.backgroundColor = [UIColor purpleColor];
[lbl1 setTextColor:[UIColor blackColor]];
int storyIndex = [indexPath indexAtPosition: [indexPath length] - 1];
if (storyIndex == 0 && FlagS)
{
NSMutableArray * SIR = [[NSUserDefaults standardUserDefaults] objectForKey:#"sizingSheet"];
NSString * SID = [[SIR objectAtIndex: storyIndex] objectForKey: #"sizing_id"];
NSString *DID = [[SIR objectAtIndex: storyIndex] objectForKey: #"data_id"];
Request = [[restRequestManager alloc]init];
NSString *SDD = [NSString stringWithFormat:#"%#%#%#%#%#", #"sizing_id=", SID, #"&", #"data_id=", DID];
NSData* Mimage = [Request restTestRequesterImage:#"http://www.stackoverflow.com" serviceUri:#"question/Post" parameters:SDD technique:#"POST"];
cell.imageView.image = [UIImage imageWithData:Mimage];
return cell;
}
searchString = #"TH_MEASURE_CATEGORY_";
str=[category objectAtIndex:storyIndex];
NSArray *array = [[NSMutableArray alloc]init];
array = [str componentsSeparatedByString:#"#"];
for (NSString *tempStr in array) {
NSComparisonResult result = [tempStr compare:searchString options:(NSCaseInsensitiveSearch) range:NSMakeRange(0, [searchString length])];
if (result == NSOrderedSame) {
lbl1.text = [category objectAtIndex: storyIndex];
lbl1.text = [lbl1.text substringFromIndex: MIN(20, [lbl1.text length])];
[cell.contentView addSubview:lbl1];
}
else{
lbl1.text = [category objectAtIndex: storyIndex];
[cell.contentView addSubview:lbl1];
}
}
return cell;
}
and the .h without all the useless stuff
#interface MeasuresViewController: UIViewController <CollapseClickDelegate,UITextFieldDelegate, UITableViewDelegate, UITableViewDelegate> {
IBOutlet UIView *test1View;
IBOutlet UIView *test2View;
IBOutlet UIView *test3View;
__weak IBOutlet CollapseClick *myCollapseClick;
IBOutlet UITableView * newsTable;
BOOL *FlagS;
UIActivityIndicatorView * activityIndicator;
CGSize cellSize;
NSMutableArray * stories;
NSMutableString * currentCategory, * currentSubcategory, * currentValue, * currentName, * currentSrc;
NSDictionary *data, *data1, *data2, *data3, *data4;
}
- (void)parseXMLFileAtURL:(NSString *)URL;
-(BOOL)ifStringExists:(NSString *)stringSentToCheck selectYourCheckArray:(NSMutableArray *)SelectedArray;
#property (nonatomic, strong) NSMutableArray *photos;
#property (atomic, strong) NSMutableArray *assets;
#end
You commented out the line that sets the data source. If a data source is not set then cellForRowAtIndexPath: will not be called.
Your current viewDidLoad code is:
- (void)viewDidLoad {
[super viewDidLoad];
newsTable = [[UITableView alloc] initWithFrame:[[UIScreen mainScreen] bounds] style:UITableViewCellStyleDefault];
newsTable.delegate = self;
//newsTable.dataSource = self;
myCollapseClick.CollapseClickDelegate = self;
[myCollapseClick reloadCollapseClick];
// If you want a cell open on load, run this method:
[myCollapseClick openCollapseClickCellAtIndex:0 animated:YES];
/*
// If you'd like multiple cells open on load, create an NSArray of NSNumbers
// with each NSNumber corresponding to the index you'd like to open.
// - This will open Cells at indexes 0,2 automatically
NSArray *indexArray = #[[NSNumber numberWithInt:0],[NSNumber numberWithInt:2]];
[myCollapseClick openCollapseClickCellsWithIndexes:indexArray animated:NO];
*/
}
Change it to
- (void)viewDidLoad
{
[super viewDidLoad];
newsTable = [[UITableView alloc] initWithFrame:[[UIScreen mainScreen] bounds] style:UITableViewCellStyleDefault];
newsTable.delegate = self;
newsTable.dataSource = self;
myCollapseClick.CollapseClickDelegate = self;
[myCollapseClick reloadCollapseClick];
// If you want a cell open on load, run this method:
[myCollapseClick openCollapseClickCellAtIndex:0 animated:YES];
/*
// If you'd like multiple cells open on load, create an NSArray of NSNumbers
// with each NSNumber corresponding to the index you'd like to open.
// - This will open Cells at indexes 0,2 automatically
NSArray *indexArray = #[[NSNumber numberWithInt:0],[NSNumber numberWithInt:2]];
[myCollapseClick openCollapseClickCellsWithIndexes:indexArray animated:NO];
*/
}

iOS 6.0- UIAlertView failed to addSubview. Works fine in lower version

This is my code to show the table view inside alert view. Its working perfectly in iOS 5.1. But in iOS 6.0 it doesnt show the table view inside alert view.
UIAlertTableView.h
#import <UIKit/UIKit.h>
#class UIAlertView;
#interface UIAlertTableView : UIAlertView {
// The Alert View to decorate
UIAlertView *alertView;
// The Table View to display
UITableView *tableView;
// Height of the table
int tableHeight;
// Space the Table requires (incl. padding)
int tableExtHeight;
id<UITableViewDataSource> dataSource;
id<UITableViewDelegate> tableDelegate;
NSArray *names;
NSArray *prices;
NSString *priceText;
NSInteger rowsCount;
NSInteger total;
}
#property (nonatomic, assign) id dataSource;
#property (nonatomic, assign) id tableDelegate;
#property (nonatomic, readonly) UITableView *tableView;
#property (nonatomic, assign) int tableHeight;
#property (nonatomic, assign) NSInteger total;
- (void)prepare;
#end
UIAlertTableView.m
#import "UIAlertTableView.h"
#define kTablePadding 8.0f
#interface UIAlertView (private)
- (void)layoutAnimated:(BOOL)fp8;
#end
#implementation UIAlertTableView
#synthesize dataSource;
#synthesize tableDelegate;
#synthesize tableHeight;
#synthesize tableView;
#synthesize total;
- (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
UIView *lowestView;
int i = 0;
while (![[self.subviews objectAtIndex:i] isKindOfClass:[UIControl class]]) {
lowestView = [self.subviews objectAtIndex:i];
i++;
}
CGFloat tableWidth = 262.0f;
tableView.frame = CGRectMake(11.0f, lowestView.frame.origin.y + lowestView.frame.size.height + 2 * kTablePadding, tableWidth, tableHeight);
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.total = 0;
[self prepare];
[super show];
}
- (NSInteger)tableView:(UITableView *)alerttableView numberOfRowsInSection:(NSInteger)section
{
/*
code to show some app data in rows
// NSMutableDictionary *rowsUponDict = [AppDelegate productsPFObjectDictionaryAppDelegate];
NSMutableArray *productsNames = [AppDelegate productsPFObjectDictionaryNamesAppDelegate];
// rowsCount = [[rowsUponDict allKeys] count];
rowsCount = [productsNames count];
NSLog(#"rowsUponDict count: %d",rowsCount);
return rowsCount+1;
*/
return 1;
}
- (UITableViewCell *)tableView:(UITableView *)alerttableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"LazyTableCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle
reuseIdentifier:CellIdentifier] autorelease];
cell.selectionStyle = UITableViewCellSelectionStyleBlue;
}
/*
code to show some app data in rows
if (indexPath.row == rowsCount) {
cell.textLabel.text = #"Total Amount:";
cell.detailTextLabel.text = [NSString stringWithFormat:#"%d",self.total];
}
else {
cell.textLabel.text = [names objectAtIndex:indexPath.row];
priceText = [NSString stringWithFormat:#"%#", [prices objectAtIndex:indexPath.row]];
cell.detailTextLabel.text = [NSString stringWithFormat:#"Rs.%#",priceText];
}
*/
return cell;
}
- (void)prepare {
if (tableHeight == 0) {
tableHeight = 250.0f;
}
/*
calculation os some app data
NSInteger priceInt;
names = [[NSArray alloc] initWithArray:[AppDelegate productsPFObjectDictionaryNamesAppDelegate]];
NSLog(#"Names: %#",names);
prices = [[NSArray alloc] initWithArray:[AppDelegate productsPFObjectDictionaryPricesAppDelegate]];
NSLog(#"prices: %#",prices);
for (int i=0; i<[prices count]; i++) {
priceText = [NSString stringWithFormat:#"%#", [prices objectAtIndex:i]];
priceInt = [priceText integerValue];
self.total = self.total + priceInt;
NSLog(#"tatal: %d",self.total);
}
*/
tableExtHeight = tableHeight + 2 * kTablePadding;
tableView = [[UITableView alloc] initWithFrame:CGRectMake(0.0f, 0.0f, 0.0f, 0.0f) style:UITableViewStylePlain];
tableView.delegate = tableDelegate;
tableView.dataSource = dataSource;
[self addSubview:tableView];
// [self insertSubview:tableView atIndex:0];
[self setNeedsLayout];
}
- (void)dealloc {
[tableView release];
[super dealloc];
}
#end
This is how I use it
UIAlertTableView *popUpCartItems = [[UIAlertTableView alloc] initWithTitle:#"Cart" message:nil delegate:self cancelButtonTitle:#"Close" otherButtonTitles:#"CheckOut",nil];
popUpCartItems.tableDelegate = popUpCartItems;
popUpCartItems.dataSource = popUpCartItems;
popUpCartItems.tableHeight = 132;
[popUpCartItems show];
Any help is greatly appreciated
Check the following link
https://github.com/simonb/SBTableAlert
I tested on both iOS 5.0 and iOS 6.0 and its work perfectly for me.
You just need to do download that code and use in your project.
Hope this will help you !!!
Try setting a frame for your tableview before adding it to UIAlertView. May be as follows.
tableView.frame = CGRectMake(0, 0, 280, 100);
[self addSubview:tableView];

iOS UITableView content not loading - Property access result unused

I'm trying to load a table with content from Twitter. The table is in a UIView and being created in the drawRect()...but I keep getting a warning:
Property access result unused - getters should not be used for side effects
on each.
Nothing show up in my table.
Here's my .h file:
#import <UIKit/UIKit.h>
#import <QuartzCore/QuartzCore.h>
#import <Twitter/Twitter.h>
#import "ColorController.h"
#interface TwitterController : UIView <UITableViewDelegate, UITableViewDataSource> {
UIButton* btnCloseView;
UITableView* tblTweets;
UIImageView* imgTwitterIcon;
ColorController* colorManager;
NSMutableArray* tweetsArray;
NSString* twitterID;
}
#property (nonatomic, retain) NSString* twitterID;
- (void) getTweets;
- (void) closeWin;
#end
and my .m
#import "TwitterController.h"
#implementation TwitterController
#synthesize twitterID;
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
colorManager = [ColorController new];
}
return self;
}
- (void)drawRect:(CGRect)rect {
imgTwitterIcon = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"imgTwitterBird"]];
CGRect twitterIconFrame = [imgTwitterIcon frame];
twitterIconFrame.origin.x = 50.0;
twitterIconFrame.origin.y = 20.0;
tblTweets = [[UITableView alloc] initWithFrame:CGRectMake(50.0, 25.0, 220.0, 500.0)];
tblTweets.separatorStyle = UITableViewCellSeparatorStyleSingleLine;
tblTweets.separatorColor = [colorManager setColor:176.0:196.0:222.0];
tblTweets.layer.borderWidth = 1.0;
tblTweets.rowHeight = 20.0;
tblTweets.scrollEnabled = YES;
tblTweets.delegate.self;
tblTweets.dataSource.self;
UIImage* imgCloseButton = [UIImage imageNamed:#"btnCloseWindow.png"];
CGSize imageSize = imgCloseButton.size;
btnCloseView = [[UIButton alloc] initWithFrame: CGRectMake(220.0, 550.0, imageSize.width, imageSize.height)];
[btnCloseView setImage:[UIImage imageNamed:#"btnCloseWindow.png"] forState:UIControlStateNormal];
[btnCloseView addTarget:self action:#selector(closeWin:) forControlEvents:UIControlEventTouchUpInside];
[self getTweets];
[self addSubview:tblTweets];
[self addSubview:imgTwitterIcon];
[self addSubview:btnCloseView];
}
- (void) getTweets {
//array to hold tweets
tweetsArray = [[NSMutableArray alloc] init];
///set up a NSURL to the twitter API
NSURL* twitterAPI = [NSURL URLWithString:[NSString stringWithFormat:#"https://api.twitter.com/1/statuses/user_timeline.json?include_entities=true&include_rts=true&screen_name=%#&count=10", twitterID]];
//get last 10 tweets (max is 20)
TWRequest *twitterRequest = [[TWRequest alloc] initWithURL:twitterAPI
parameters:nil requestMethod:TWRequestMethodGET];
// Notice this is a block, it is the handler to process the response
[twitterRequest performRequestWithHandler:^(NSData *responseData, NSHTTPURLResponse *urlResponse, NSError *error) {
if ([urlResponse statusCode] == 200) {
// The response from Twitter is in JSON format
// Move the response into a dictionary and print
NSError *error;
NSDictionary *tweetsDict = [NSJSONSerialization JSONObjectWithData:responseData options:0 error:&error];
for(NSDictionary* thisTweetDict in tweetsDict) {
[tweetsArray addObject:[thisTweetDict objectForKey:#"text"]];
}
[tblTweets reloadData];
}
else
NSLog(#"Twitter error, HTTP response: %i", [urlResponse statusCode]);
}];
}
#pragma mark Table Management
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return [tweetsArray count];
NSLog(#"%i", [tweetsArray count]);
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return [tweetsArray count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"tableCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
cell.textLabel.textColor = [UIColor colorWithRed:66.0/255.0 green:66.0/255.0 blue:66.0/255.0 alpha:1];
cell.textLabel.font = [UIFont fontWithName:#"Helvetica-Bold" size: 13.0];
cell.textLabel.text = [tweetsArray objectAtIndex:indexPath.row];
CGRect cellFrame = [cell frame];
cellFrame.size.height = 25.0;
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
NSString* thisTweet = [tweetsArray objectAtIndex:indexPath.row];
}
#pragma mark Close Window
- (void) closeWin {
NSMutableDictionary* userData = [[NSMutableDictionary alloc] init];
[userData setObject:#"closeTwitter" forKey:#"theEvent"];
[[NSNotificationCenter defaultCenter] postNotificationName:#"theMessenger" object:self userInfo: userData];
}
#end
drawRect is used to draw stuff inside this views, using drawing functions
You should move your views additions to the layoutSubviews
Instead of - (void)drawRect:(CGRect)rect use - (void)layoutSubviews
This may or may not solve your issues, but nevertheless its the correct approach

GCD and KVO problems

My app is want to get the albums list of the iphone and all the photos in certain album.
In the app I enumerate the photos in one album of the iphone.
As there may be lots of photos of certain album, considering of performance I use GCD:dispatch_async. But it always crashes when the tableview cell updates which is invoked by KVO.
I've no idea about whether I use KVO or GCD in a wrong way.
Now alternatively I use performSelectorInBackground: replacing of dispatch_async. Now the app is not crashed but the app's performance is poor: the title of the cell will only be shown when you touch on it or scroll the tableview when there are many photos. In other words, the main thread must be blocked.
Attached is the code and the core code is in AlbumListViewController.m.
Can any one help me to check it ?
I just want to know:
1 why the app is crashed if using dispatch_async
2 how can I improve the performance in case of many photos.
thanks.
Below is my Code:
//
// RootViewController.h
// AlbumDemo
#import
#interface RootViewController : UITableViewController {
NSMutableArray *_listArray;
}
#property (nonatomic, retain) NSMutableArray *listArray;
#end
// RootViewController.m
#import "RootViewController.h"
#import
#import "AlbumListViewController.h"
NSString *thumnail = #"thumnail";
NSString *albumName = #"albumName";
NSString *albumNum = #"albumNum";
NSString *albumGroup = #"albumGroup";
#implementation RootViewController
#synthesize listArray = _listArray;
#pragma -
#pragma Function
- (void)setUp
{
_listArray = [[NSMutableArray alloc] initWithCapacity:1];
self.title = #"Albums";
}
- (void)fetchAlbumList
{
ALAssetsLibrary *assetLib = [[[ALAssetsLibrary alloc] init] autorelease];
ALAssetsFilter *fileter = [ALAssetsFilter allPhotos];
[assetLib enumerateGroupsWithTypes:ALAssetsGroupAll
usingBlock:^(ALAssetsGroup *group, BOOL *stop)
{
if (group)
{
[group setAssetsFilter:fileter];
NSString *_groupName = [group valueForProperty:ALAssetsGroupPropertyName];
NSNumber *_groupNum = [NSNumber numberWithInteger:[group numberOfAssets]];
UIImage *_groupImage = [UIImage imageWithCGImage:[group posterImage]];
NSDictionary *dic = [NSDictionary dictionaryWithObjectsAndKeys:_groupName,albumName,_groupNum,albumNum,_groupImage,thumnail,group,albumGroup, nil];
[_listArray addObject:dic];
[self.tableView reloadData];
}
else
{
NSLog(#"_listArray :%#",_listArray);
}
}
failureBlock:^(NSError *error)
{
NSLog(#"Error: %#", error);;
}
];
}
#pragma -
#pragma ViewController lift cycle
- (void)viewDidLoad
{
[super viewDidLoad];
[self setUp];
[self fetchAlbumList];
}
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
}
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
}
- (void)viewWillDisappear:(BOOL)animated
{
[super viewWillDisappear:animated];
}
- (void)viewDidDisappear:(BOOL)animated
{
[super viewDidDisappear:animated];
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
return 50;
}
// Customize the number of sections in the table view.
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [_listArray count];
}
// Customize the appearance of table view cells.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UILabel *nameLab = nil;
UILabel *numLab = nil;
UIImageView *thumnailImage = nil;
UIFont *font = [UIFont boldSystemFontOfSize:18];
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
thumnailImage = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0,50, 50)];
thumnailImage.tag = 100;
[cell.contentView addSubview:thumnailImage];
[thumnailImage release];
nameLab = [[UILabel alloc] initWithFrame:CGRectMake(60, 10, 100, 30)];
nameLab.tag = 200;
nameLab.backgroundColor = [UIColor clearColor];
nameLab.font = font;
[cell.contentView addSubview:nameLab];
[nameLab release];
numLab = [[UILabel alloc] initWithFrame:CGRectMake(200, 10, 50, 30)];
numLab.tag = 300;
numLab.backgroundColor = [UIColor clearColor];
numLab.textColor = [UIColor grayColor];
numLab.font = font;
[cell.contentView addSubview:numLab];
[numLab release];
}
else
{
thumnailImage = (UIImageView *)[cell.contentView viewWithTag:100];
nameLab = (UILabel *)[cell.contentView viewWithTag:200];
numLab = (UILabel *)[cell.contentView viewWithTag:300];
}
NSDictionary *dic = [self.listArray objectAtIndex:indexPath.row];
thumnailImage.image = (UIImage *)[dic valueForKey:thumnail];
NSString *title = [dic valueForKey:albumName];
CGSize titleSize = [title sizeWithFont:font];
CGRect rect = nameLab.frame;
rect.size = titleSize;
nameLab.frame = rect;
nameLab.text = title;
rect = numLab.frame;
rect.origin.x = 60 + nameLab.frame.size.width + 10;
numLab.frame = rect;
numLab.text = [NSString stringWithFormat:#"(%d)",[[dic valueForKey:albumNum] intValue]];
// Configure the cell.
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
NSDictionary *dic = [self.listArray objectAtIndex:indexPath.row];
AlbumListViewController *viewController = [[AlbumListViewController alloc] initWithAssetGroup:[dic valueForKey:albumGroup]];
[self.navigationController pushViewController:viewController animated:YES];
[viewController release];
[tableView deselectRowAtIndexPath:indexPath animated:YES];
}
- (void)didReceiveMemoryWarning
{
// Releases the view if it doesn't have a superview.
[super didReceiveMemoryWarning];
// Relinquish ownership any cached data, images, etc that aren't in use.
}
- (void)viewDidUnload
{
[super viewDidUnload];
// Relinquish ownership of anything that can be recreated in viewDidLoad or on demand.
// For example: self.myOutlet = nil;
}
- (void)dealloc
{
My_Release (_listArray);
[super dealloc];
}
#end
// AlbumListViewController.h
// AlbumDemo
#import
#import
#interface AlbumListViewController : UITableViewController {
NSMutableArray *_marr;
ALAssetsGroup *_assetsGroup;
}
#property (nonatomic, retain) NSMutableArray *list;
#property (nonatomic, retain) ALAssetsGroup *assetsGroup;
- (id)initWithAssetGroup:(ALAssetsGroup *)group;
#end
// AlbumListViewController.m
// AlbumDemo
#import "AlbumListViewController.h"
#interface PhotoObj : NSObject {
NSString *_name;
UIImage *_thumbnail;
UIImage *_fullImage;
}
#property (nonatomic, copy ) NSString *name;
#property (nonatomic, retain) UIImage *thumbnail;
#property (nonatomic, retain) UIImage *fullImage;
#end
#implementation PhotoObj
#synthesize name = _name;
#synthesize thumbnail = _thumbnail,fullImage = _fullImage;
- (void)dealloc
{
My_Release(_thumbnail);
My_Release(_fullImage);
My_Release(_name);
[super dealloc];
}
#end
#interface AlbumListViewController()
- (NSMutableArray*)list;
- (NSUInteger)countOfList;
- (id)objectInListAtIndex:(NSUInteger)idx;
- (void)insertObject:(id)anObject inListAtIndex:(NSUInteger)idx;
- (id)objectInListAtIndex:(NSUInteger)idx;
- (void)removeObjectFromListAtIndex:(NSUInteger)idx;
- (void)replaceObjectInListAtIndex:(NSUInteger)idx withObject:(id)anObject;
- (void)setList:(NSMutableArray *)_arr;
#end
#implementation AlbumListViewController
#synthesize assetsGroup = _assetsGroup;
- (id)initWithAssetGroup:(ALAssetsGroup *)group
{
self = [self initWithStyle:UITableViewStylePlain];
if (self )
{
_marr = [[NSMutableArray alloc] initWithCapacity:1];
self.assetsGroup = group;
self.tableView.delegate = self;
self.tableView.dataSource = self;
}
return self;
}
- (id)initWithStyle:(UITableViewStyle)style
{
self = [super initWithStyle:style];
if (self) {
// Custom initialization
}
return self;
}
- (void)dealloc
{
My_Release(_marr);
My_Release(_assetsGroup);
[self removeObserver:self forKeyPath:#"list"];
[super dealloc];
}
- (void)didReceiveMemoryWarning
{
// Releases the view if it doesn't have a superview.
[super didReceiveMemoryWarning];
}
#pragma mark - View lifecycle
- (void)parseAssetGroup
{
[_marr removeAllObjects];
[self.assetsGroup enumerateAssetsUsingBlock:^(ALAsset *result, NSUInteger index, BOOL *stop) {
if (result)
{
PhotoObj *obj = [[PhotoObj alloc] init];
obj.thumbnail = [UIImage imageWithCGImage:[result thumbnail]];
ALAssetRepresentation *represention = [result defaultRepresentation];
obj.fullImage = [UIImage imageWithCGImage:[represention fullScreenImage]];
obj.name = [[represention url] absoluteString];
[self willChangeValueForKey:#"list"];
[self insertObject:obj inListAtIndex:[_marr count]];
[self didChangeValueForKey:#"list"];
My_Release(obj);
}
}];
}
- (void)viewDidLoad
{
[super viewDidLoad];
[self addObserver:self forKeyPath:#"list" options:NSKeyValueObservingOptionNew |NSKeyValueObservingOptionOld context:NULL];
/*
if performSelectorInBackground, the perofrmance is poor
as the title of the cell will be shown in a long time and it now seems the main thread is blocked
*/
[self performSelectorInBackground:#selector(parseAssetGroup) withObject:nil];
/*
using dispatch_async it always crashes
as it says the sth is wrong with the tableview update
*/
// dispatch_async(dispatch_get_main_queue(), ^{
// [self parseAssetGroup];
// });
}
- (void)viewDidUnload
{
[super viewDidUnload];
}
#pragma mark - Table view data source
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
return 50;
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
// Return the number of sections.
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
// Return the number of rows in the section.
return [_marr count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UIImageView *thumbNail = nil;
UILabel *nameLab = nil;
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
thumbNail = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 50, 50)];
thumbNail.tag = 99;
[cell.contentView addSubview:thumbNail];
[thumbNail release];
nameLab = [[UILabel alloc] initWithFrame:CGRectMake(60, 10, 240, 40)];
nameLab.numberOfLines = 2;
nameLab.font = [UIFont systemFontOfSize:16];
nameLab.tag = 199;
[cell.contentView addSubview:nameLab];
[nameLab release];
}
else
{
thumbNail = (UIImageView *)[cell.contentView viewWithTag:99];
nameLab = (UILabel *)[cell.contentView viewWithTag:199];
}
// Configure the cell...
PhotoObj *obj = [_marr objectAtIndex:indexPath.row];
nameLab.text = obj.name;
thumbNail.image = obj.thumbnail;
return cell;
}
#pragma mark -
- (NSUInteger)countOfList
{
return [_marr count];
}
- (NSMutableArray*)list
{
return _marr;
}
- (void)setList:(NSMutableArray *)_arr
{
if (_marr != _arr)
{
[_marr release];
_marr = _arr;
}
}
- (id)objectInListAtIndex:(NSUInteger)idx
{
return [_marr objectAtIndex:idx];
}
- (void)insertObject:(id)anObject inListAtIndex:(NSUInteger)idx
{
if ([NSThread isMainThread])
{
NSLog(#"insert main thread");
}
else
{
NSLog(#"insert not main thread");
}
[_marr insertObject:anObject atIndex:idx];
}
- (void)removeObjectFromListAtIndex:(NSUInteger)idx
{
[_marr removeObjectAtIndex:idx];
}
- (void)replaceObjectInListAtIndex:(NSUInteger)idx withObject:(id)anObject
{
[_marr replaceObjectAtIndex:idx withObject:anObject];
}
- (void)observeValueForKeyPath:(NSString *)keyPath
ofObject:(id)object
change:(NSDictionary *)change
context:(void *)context
{
NSIndexSet *indices = [change objectForKey:NSKeyValueChangeIndexesKey];
if (indices == nil)
return; // Nothing to do
// Build index paths from index sets
NSUInteger indexCount = [indices count];
NSUInteger buffer[indexCount];
[indices getIndexes:buffer maxCount:indexCount inIndexRange:nil];
NSMutableArray *indexPathArray = [NSMutableArray array];
for (int i = 0; i
I ran into exactly the same problem today. In short, the reason is you cannot do UIKit related tasks, like updating a table, or in my case a Textview, from the background dispatch queue. Check the link below for more details.
comparison GCD vs. performSelectorInBackground: dispatch_async not in background
A possible solution is the following: instead of assigning your fresh data in your update block directly to the KVO variable which causes the crash, you dispatch another block which does this to the main queue, from inside your update block. If you use the dispatch_async_f function to do this, you can pass a pointer to your data as context.
Like this:
dispatch_async(yourQueue, ^() {
NSArray *data;
// do stuff to alloc and fill the array
// ...
dispatch_async(dispatch_get_main_queue(), ^() {
myObj.data = data; // the assignment, which triggers the KVO.
});
});
For me this works without retaining and releasing the data. Not sure, if this correct.

Resources