I have a one major issue. I have implemented a uitable view with paging but when i reach to row 700 application crashed also sometimes it restart the ipad. So i tried every thing but i am not getting solution. this is my code.
#pragma mark - Table View
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
if (dataArray.count<[self.allRecordCount intValue])
{
return dataArray.count+1;
}
return dataArray.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
if (dataArray.count<[self.allRecordCount intValue])
{
if (indexPath.row < dataArray.count) {
return [self dataCellForIndexPath:indexPath tableview:tableView];
} else {
return [self loadingCell];
}
}else{
return [self dataCellForIndexPath:indexPath tableview:tableView];
}
}
- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath {
if (cell.tag == kLoadingCellTag) {
[self fillDataArray];
}
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
return 150;
}
#pragma mark PAGING_LOGIC
-(void)fillDataArray
{
self.strStartPoint=[NSString stringWithFormat:#"%d",[dataArray count]];
self.strPageSize=[NSString stringWithFormat:#"%d",kPageSize];
NSMutableArray *temp=[manager returnCallArray:self.strStartPoint NoofRecord:self.strPageSize];
for (Call *obj in temp)
{
[dataArray addObject:obj];
}
[temp release];
[tbl reloadData];
}
- (UITableViewCell *)loadingCell {
UITableViewCell *cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:nil] autorelease];
UIActivityIndicatorView *activityIndicator = [[UIActivityIndicatorView alloc]
initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhiteLarge];
activityIndicator.frame=CGRectMake(480.5f,52.5f , 45, 45);
[cell addSubview:activityIndicator];
[activityIndicator release];
[activityIndicator startAnimating];
cell.tag = kLoadingCellTag;
return cell;
}
- (UITableViewCell *)dataCellForIndexPath:(NSIndexPath *)indexPath tableview:(UITableView *)table
{
NSString *CellIdentifier = [NSString stringWithFormat:#"%d %d",indexPath.section,indexPath.row];
UITableViewCell *cell = [table dequeueReusableCellWithIdentifier:CellIdentifier];
if(table.tag == 0){
//cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
UILabel *lblCall;UILabel *lblCallText;UILabel *lblAirComment;UILabel *lblCustomerTxt;UILabel *lblProximityTxt;
UILabel *lblNoOfMachineTxt;
UILabel *lblCallReceiveTxt;
UILabel *lblCallDueTxt;
if (cell==nil) {
Call *temp = [dataArray objectAtIndex:indexPath.row];
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle
reuseIdentifier:CellIdentifier] autorelease];
lblCall = [[UILabel alloc]initWithFrame:CGRectMake(20,setY,220,20)];
lblCall.backgroundColor = [UIColor clearColor];
lblCall.text = #"Call Priority/Type/Status";
[cell.contentView addSubview:lblCall];
[lblCall release];
lblCallText = [[UILabel alloc]initWithFrame:CGRectMake(220,setY,270,20)];
lblCallText.backgroundColor = [UIColor clearColor];
lblCallText.tag = indexPath.row+100;
[cell.contentView addSubview:lblCallText];
[lblCallText release];
lbl_strstatusChangeReason = [[UILabel alloc] init];/
lbl_strstatusChangeReason.frame=CGRectMake(20,setY,800, labelSize5.height);
lbl_strstatusChangeReason.backgroundColor = [UIColor clearColor];
lbl_strstatusChangeReason.text = str_changeStatusReasoon;
lbl_strstatusChangeReason.tag = indexPath.row + 200000;
lbl_strstatusChangeReason.numberOfLines = 0;
lbl_strstatusChangeReason.lineBreakMode = UILineBreakModeWordWrap;
lbl_strstatusChangeReason.textColor = [UIColor redColor];
[cell.contentView addSubview:lbl_strstatusChangeReason];
}
return cell;
}
This is my NSObject which i use for filling cell.
#import <Foundation/Foundation.h>
#interface Call : NSObject {
NSString *strType;
NSString *strTypePriority;
NSString *strCustomer;
NSString *strProximity;
NSString *strETADateTime;
NSString *str480;
NSString *strAirComment;
NSString *strProblemDesc;
NSString *strNumberOfMachine;
NSString *strCallReceived;
NSString *strCallDue;
NSString *strAssignedTech;
NSString *strAssignedTechName;
NSString *strDefaultTech;
NSString *strDefaultTechName;
NSString *strDispatchedBy;
}
#property(nonatomic,retain)NSString *strDispatchedToTechInterval;
#property(nonatomic,retain)NSString *strDispatchedToBranchInterval;
#property(nonatomic,retain)NSString *strDispatchToTechnicianDate;
#property(nonatomic,retain)NSString *strDispatchToTechnicianTime;
#property(nonatomic,retain)NSString *strDispatchToTechnicianFrom;
#property(nonatomic,retain)NSString *strDispatchToTechnicianBy;
#property(nonatomic,retain)NSString *strCallClosedDateAndTimeSorting;
#property(nonatomic,retain)NSString *strCallClosedDateAndTime;
#property(nonatomic,retain)NSString *strCallClosedDate;
#property(nonatomic,retain)NSString *strCallClosedTime;
#property(nonatomic,retain)NSString *strtotalAmount;
#property(nonatomic,retain)NSString *strtotalPartAmount;
#property(nonatomic,retain)NSString *strtotalChargeAmount;
#property(nonatomic,retain)NSString *strOriginatingFacility;
#property(nonatomic,retain)NSString *str_RecordVersionNumber;
#property(nonatomic,retain)NSString *str_CustomerLatitude;
#property(nonatomic,retain)NSString *str_CustomerLongitude;
#property(nonatomic,retain)NSString *strDiscount;
#property(nonatomic,retain)NSString *str_HdrComment1;
#property(nonatomic,retain)NSString *str_PrioritySortValue;
#property(nonatomic,retain)NSString *str_StatusChangeReason;
#property(nonatomic,retain)NSString *str_OnSiteDate;
#property(nonatomic,retain)NSString *str_Address;
#property(nonatomic,retain)NSString *str_Address1;
#property(nonatomic,retain)NSString *str_Address2;
#property(nonatomic,retain)NSString *str_City;
#property(nonatomic,retain)NSString *str_State;
#property(nonatomic,retain)NSString *str_Zip;
#property(nonatomic,retain)NSString *strStatus;
#property(nonatomic,retain)NSString *strTypePriority;
#property(nonatomic,retain)NSString *strCustomer;
#property(nonatomic,retain)NSString *strProximity;
#property(nonatomic,retain)NSString *str480;
#property(nonatomic,retain)NSString *strAirComment;
#property(nonatomic,retain)NSString *strProblemDesc;
#property(nonatomic,retain)NSString *strNumberOfMachine;
#property(nonatomic,retain)NSString *strCallReceived;
#property(nonatomic,retain)NSString *strCallDue;
#property(nonatomic,retain)NSString *strAssignedTech;
#property(nonatomic,retain)NSString *strDefaultTech;
#property(nonatomic,retain)NSString *strDispatchedBy;
#end
#import "Call.h"
#implementation Call
#synthesize strStatus;
#synthesize strTypePriority;
#synthesize strCustomer;
#synthesize strProximity;
#synthesize str480;
#synthesize strAirComment;
#synthesize strProblemDesc;
#synthesize strNumberOfMachine;
#synthesize strCallReceived;
#synthesize strCallDue;
#synthesize strAssignedTech;
#synthesize strDefaultTech;
#synthesize strDispatchedBy;
#synthesize strCallNumber;
#synthesize strHoldCall;
#synthesize strOpenCall;
#synthesize strLoactionId;
#synthesize strCustomerName;
#synthesize strContactName;
#synthesize strPhoneNo;
#synthesize strFirsMachine;
#synthesize strMachineDone;
#synthesize strDispatchedToBranch;
#synthesize strDispatchedToTech;
#synthesize strServiceDue;
#synthesize strCallComment;
#synthesize strDiscount;
- (void)dealloc {
[strStatus release];
[strTypePriority release];
[strCustomer release];
[strProximity release];
[str480 release];
[strAirComment release];
[strProblemDesc release];
[strNumberOfMachine release];
[strCallReceived release];
[strCallDue release];
[strAssignedTech release];
[strDefaultTech release];
[strDispatchedBy release];
[strCallNumber release];
[strHoldCall release];
[strOpenCall release];
[strLoactionId release];
[strCustomerName release];
[strContactName release];
[strPhoneNo release];
[strFirsMachine release];
[strMachineDone release];
[strDispatchedToBranch release];
[strDispatchedToTech release];
[strServiceDue release];
[strCallComment release];
[strDiscount release];
[str_StatusChangeReason release];
[super dealloc];
}
and this is my method which i am using for filling array for paging.
-(NSMutableArray *)returnCallArray:(NSString *)startPoint NoofRecord:(NSString *)noOfRecord
{
[self initiateFMDB];
NSMutableArray *aryCallFilterData=[[NSMutableArray alloc]init];
// NSMutableArray *finalArrayCall=[[NSMutableArray alloc]init];
#try {
if(![db open]){
NSLog(#"Could not open DB");
}
else{
resultset = [db executeQuery:[NSString stringWithFormat:#"select Call_HDR.*,Problem.Machine,Problem.ServiceStatusFlag,AssignTech.RepName AS AssignTechName,DefaultTech.RepName AS DefaultTechName,Problem.ProblemDescription AS ProblemDescription,Problem.SLAHours AS SLAHours,ARComment.CustARComments As CustARComments,SLAResponseCode.SLAResponse As SLAResponse from CALL_HDR LEFT JOIN Branch_Reps as AssignTech ON CALL_HDR.RepID = AssignTech.RepID LEFT JOIN Branch_Reps as DefaultTech ON CALL_HDR.AssignedServiceRep = DefaultTech.RepID LEFT JOIN CALL_MACHINE as Problem ON CALL_HDR.CallNumber||'*001' = Problem.CallNumberWSeqnbr LEFT JOIN Customers as ARComment ON CALL_HDR.LocationID = ARComment.LocationID LEFT JOIN NA_Data as SLAResponseCode ON CALL_HDR.CustomerTypeCode = SLAResponseCode.NationalAccountCode where CALL_HDR.CallStatus IN ('%#','%#') LIMIT %#,%# ",STATUS_CLOSED,STATUS_CANCELLED,startPoint,noOfRecord]];
}
}
#catch (NSException * e) {
NSLog(#"Exception error for selectFromItemPhoto is %#",[e reason]);
}
if (!resultset) {
NSLog(#"no result set fechted");
}
while ([resultset next]) {
NSString *strCallPrioritySortValue = [resultset stringForColumn:#"PrioritySortValue"];
NSString *strCallPriority = [resultset stringForColumn:#"CallPriority"];
NSString *strCallType = [resultset stringForColumn:#"CallType"];
NSString *strCallStatus = [resultset stringForColumn:#"CallStatus"];
NSString *strCustomerName = [resultset stringForColumn:#"CustomerName"];
NSString *strAdd1 = [resultset stringForColumn:#"Address1"];
NSString *strAdd2 = [resultset stringForColumn:#"Address2"];
NSString *strCity = [resultset stringForColumn:#"City"];
NSString *strState = [resultset stringForColumn:#"State"];
NSString *strZip = [resultset stringForColumn:#"Zip"];
NSString *strCustomer=#"";
ObjModel.strStsChgByRep=strStatusChgByRep;
ObjModel.strCustomer = strCustomer;
ObjModel.strStatus = strCallStatus;
ObjModel.strHoldCall =strHoldCode;
ObjModel.strProximity = #"";
ObjModel.f_proximity = 0.0f;
ObjModel.str480 = strStr480;
ObjModel.strProblemDesc = strProbleDesc;
ObjModel.strNumberOfMachine =strNumberOfMachine;
ObjModel.strCallReceived = strCallReceive;
ObjModel.strCallDue = strCallDue;
ObjModel.strAssignedTech = strAssignedTech;
ObjModel.strDefaultTech = strDefaultTech;
ObjModel.strDispatchedBy = strDispatchedBy;
ObjModel.strCallNumber = strCallNumber;
ObjModel.n_CallNumber = [strCallNumber intValue];
ObjModel.strLoactionId = strLoactionId;
ObjModel.strContactName = strContactName;
ObjModel.strCustomerName = strCustomerName;
ObjModel.strPhoneNo = strPhoneNo;
ObjModel.strDiscount = strDisct;
ObjModel.strAirComment = strAirComment;
ObjModel.strAssigntechName = strAssignedTechBy;
ObjModel.strRepId = strRepId;
ObjModel.str_Address1 = strAdd;
ObjModel.str_StatusChangeReason = strStatusChangeReason;
[aryCallFilterData addObject:ObjModel];
[ObjModel release];
}
return aryCallFilterData;
}
So please review my code and suggest something so that i can resolve crash.
This is crash log:
Received memory warning.
2013-06-24 04:59:26.168 MFSS_PAGING_FACEBOOK[874:907] <FMDatabase: 0x2d8aa130> executeQuery: select Call_HDR.*,Problem.Machine,Problem.ServiceStatusFlag,AssignTech.RepName AS AssignTechName,DefaultTech.RepName AS DefaultTechName,Problem.ProblemDescription AS ProblemDescription,Problem.SLAHours AS SLAHours,ARComment.CustARComments As CustARComments,SLAResponseCode.SLAResponse As SLAResponse from CALL_HDR LEFT JOIN Branch_Reps as AssignTech ON CALL_HDR.RepID = AssignTech.RepID LEFT JOIN Branch_Reps as DefaultTech ON CALL_HDR.AssignedServiceRep = DefaultTech.RepID LEFT JOIN CALL_MACHINE as Problem ON CALL_HDR.CallNumber||'*001' = Problem.CallNumberWSeqnbr LEFT JOIN Customers as ARComment ON CALL_HDR.LocationID = ARComment.LocationID LEFT JOIN NA_Data as SLAResponseCode ON CALL_HDR.CustomerTypeCode = SLAResponseCode.NationalAccountCode where CALL_HDR.CallStatus IN ('8','0') LIMIT 700,100
Thanks
You should reuse your cells. You have so many UITableViewCells loaded into memory and it crashes after a memory warning.
You cell identifier (index+row) create as many cells as 700, when you are loading 700 rows of data. The cell identifier should be unique to the number of cells shown in the screen, not more than that. Best is, you can have some other easy and non looping cell identifier. So cells are reused more efficiently.
Try to use the same UITableViewCell but change the labels and detailLabels matching with your information to show.
One thing that is worth looking at is the dequeueReusableCellWithIdentifier use in your code. from what i can tell you are creating a new cell for each data item because you are using the cell section and row as and identifier. Is there a reason for this? If your cells are visually the same (Only the data for each is different) then change this so the dequeueReusableCell identifier is the same for each cell. This gives the OS the ability to manage the memory for cells more efficiently.
Related
there is a strange problem I have not met ever
there is an array() including some custom object named MyClass parsed by JSONKit;
when I keep scrolling the tableview the memory will keeping increasing too.
but when replace
cell.textLabel.text = myclass.name;
with
cell.textLabel.text = #"cool";
or
cell.textLabel.text = [NSString stringWithFormate:#"a-%d", indexPath.row];
it's ok the memory with keep stable
but if I use
cell.textLabel.text = [NSString stringWithFormate:#"a-%#-i",myclass.name, indexPath.row];
it also keep increasing;
It will drive my crazy!!
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
static NSString *identifier = #"Singers";
OMTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:identifier];
MyClass *myclass = [self.data objectAtIndex:indexPath.row];
if (cell == nil){
cell = [[[OMTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:identifier] autorelease];
}
cell.textLabel.text = myclass.name;
return cell;
}
MyClass
there is two class one Base another inherit
Base:
#interface OMBase : NSObject {
NSMutableDictionary *data;
NSString *name;
NSArray *keys;
}
#property (nonatomic, retain) NSString *name;
#property (nonatomic, copy) NSMutableDictionary *data;
#implementation OMBase
#synthesize data, name;
- (void)setData:(NSMutableDictionary *)adata{
if (data){
[data release];
data = nil;
}
data = [adata mutableCopy];
}
- (void)dealloc{
if (keys){
[keys release];
}
[data release];
[super dealloc];
}
- (id)init{
if (self = [super init]){
self.data = [[[NSMutableDictionary alloc] initWithCapacity:20] autorelease];
}
return self;
}
inherit:
#import "OMBase.h"
#interface OMLyric : OMBase
- (NSString *)songid;
- (NSString *)content;
#import "OMLyric.h"
#implementation OMLyric
- (NSString *)songid{
return [data objectForKey:#"songid"];
}
- (NSString *)content{
return [data objectForKey:#"content"];
}
Seems like your myclass.name getter returns a new allocated object. We can't say more without seeing myclass.
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];
I think just showing my whole code is better than my explanation.. actually I'm not good at expressing something in English.X(
this code is .h file for .m file below.
#import <UIKit/UIKit.h>
#define kImageValueTag 0
#define kNameValueTag 1
#define kSubtitleValueTag 2
#define kMemoValueTag 3
#class PhonebookDetailedViewController;
#interface PhonebookViewController : UIViewController <UITableViewDelegate, UITableViewDataSource>
{
UITableViewCell *tvCell;
UITableView *tableView;
UISearchBar *searchBar;
NSString *fullName;
NSMutableDictionary *names, *pictures;
NSArray *keys, *sortedKeys, *sortedAllValues;
PhonebookDetailedViewController *childController;
}
#property (nonatomic, retain) IBOutlet UITableViewCell *tvCell;
#property (nonatomic, retain) IBOutlet UISearchBar *searchBar;
#property (nonatomic, retain) IBOutlet UITableView *tableView;
#property (nonatomic, retain) UIImage *phoneImage;
#property (nonatomic, retain) NSString *fullName;
#property (nonatomic, retain) NSMutableDictionary *names;
#property (nonatomic, retain) NSMutableDictionary *pictures;
#property (nonatomic, retain) NSArray *keys;
#property (nonatomic, retain) NSArray *sortedKeys;
#property (nonatomic, retain) NSArray *sortedAllValues;
#end
this code is for the .m file that implement showing a table. When I try to scroll the table down, the error named EXC_BAD_ACCESS is suddenly called at - (NSString *)tableView: titleForHeaderInSection: method. I guess sortedKeys releases at somewhere because I can do [sortedKeys count] before error, but cannot when error comes. I don't know where it releases and why it releases, however. Please show your ideas to me. Any ideas are okay. Thank you in advance.
#import "PhonebookViewController.h"
#import "PhonebookDetailedViewController.h"
#import "NSString-SortForIndex.h"
#implementation PhonebookViewController
#synthesize tvCell;
#synthesize searchBar;
#synthesize tableView;
#synthesize phoneImage;
#synthesize fullName;
#synthesize names, pictures;
#synthesize keys, sortedAllValues, sortedKeys;
//- (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.
//}
#pragma mark - View lifecycle
- (void)viewDidLoad
{
[super viewDidLoad];
CGRect bounds = self.tableView.bounds;
bounds.origin.y = bounds.origin.y + searchBar.bounds.size.height;
self.tableView.bounds = bounds;
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *nameFilePath = [[paths objectAtIndex:0] stringByAppendingPathComponent:#"nameContacts.dict"];
NSString *pictureFilePath = [[paths objectAtIndex:0] stringByAppendingPathComponent:#"imageContacts.dict"];
self.names = (NSMutableDictionary *)[NSKeyedUnarchiver unarchiveObjectWithFile:nameFilePath];
self.pictures = (NSMutableDictionary *)[NSKeyedUnarchiver unarchiveObjectWithFile:pictureFilePath];
self.keys = [self.names allKeys];
sortedKeys = [self.keys sortedArrayUsingSelector:#selector(sortForIndex:)];
sortedAllValues = [[NSArray alloc] init];
for (NSString *sortedKey in sortedKeys)
{
NSArray *selectedValues = [self.names valueForKey:sortedKey];
for (NSString *selectedValue in selectedValues)
sortedAllValues = [sortedAllValues arrayByAddingObject:selectedValue];
}
// Do any additional setup after loading the view from its nib.
}
- (void)viewDidUnload
{
[super viewDidUnload];
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
self.tableView = nil;
self.searchBar = nil;
self.tvCell = nil;
self.fullName = nil;
self.names = nil;
self.pictures = nil;
self.keys = nil;
self.sortedKeys = nil;
self.sortedAllValues = nil;
}
- (void)dealloc
{
[tableView release];
[searchBar release];
[tvCell release];
[fullName release];
[names release];
[pictures release];
[keys release];
[sortedKeys release];
[sortedAllValues release];
[super dealloc];
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
// Return YES for supported orientations
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
#pragma mark - Table Data Source Methods
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return [sortedKeys count];
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
NSString *key = [sortedKeys objectAtIndex:section];
NSArray *nameSection = [names objectForKey:key];
return [nameSection count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CustomCellIdentifier = #"CustomCellIdentifier";
UITableViewCell *cell = [self.tableView dequeueReusableCellWithIdentifier:CustomCellIdentifier];
if ( cell == nil )
{
NSArray *nib = [[NSBundle mainBundle]
loadNibNamed:#"CustomPhonebookCell"
owner:self
options:nil];
if (nib.count > 0)
{
cell = self.tvCell;
} else
{
NSLog(#"Failed to load CustomPhonebookCell nib file!");
}
}
cell.accessoryType = UITableViewCellAccessoryDetailDisclosureButton;
NSUInteger row = [indexPath row];
NSUInteger section = [indexPath section];
NSString *foundKey = [sortedKeys objectAtIndex:section];
NSArray *nameSection = [self.names objectForKey:foundKey];
UILabel *nameLabel = (UILabel *)[cell viewWithTag:kNameValueTag];
nameLabel.text = [nameSection objectAtIndex:row];
return cell;
}
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
{
NSString *key = [sortedKeys objectAtIndex:section]; // EXC_BAD_ACCESS error at here
return key;
}
sortedKeys is not properly retained. When you set it use self.
self.sortedKeys = [self.keys sortedArrayUsingSelector:#selector(sortForIndex:)];
I think I'm not getting the handle on address book and UITableView, or maybe I'm just making it simpler than it is.
here is my .h file:
#interface Contacts : UITableViewController <ABPeoplePickerNavigationControllerDelegate> {
NSMutableArray *menuArray;
NSString *firstName;
NSString *lastName;
UIButton *addcontact;
}
#property (nonatomic, retain) NSMutableArray *menuArray;
#property (nonatomic, strong) UIButton *addcontact;
#property (nonatomic, strong) NSString *firstName;
#property (nonatomic, strong) NSString *lastName;
-(void)showPeoplePickerController;
#end
And my .m file:
-(IBAction)addcontact:(id)sender {
ABPeoplePickerNavigationController *peoplePicker=[[ABPeoplePickerNavigationController alloc] init];
[peoplePicker setPeoplePickerDelegate:self];
[self presentModalViewController:peoplePicker animated:YES]; }
- (void)viewDidLoad
{
menuArray = [[NSMutableArray alloc] init];
[super viewDidLoad];
}
- (BOOL)peoplePickerNavigationController:
(ABPeoplePickerNavigationController *)peoplePicker
shouldContinueAfterSelectingPerson:(ABRecordRef)person {
firstName = (__bridge NSString *)ABRecordCopyValue(person, kABPersonFirstNameProperty);
[menuArray addObject:firstName];
lastName = (__bridge NSString *)ABRecordCopyValue(person, kABPersonLastNameProperty);
[menuArray addObject:lastName];
[self dismissModalViewControllerAnimated:YES];
return NO;}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [menuArray 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];
}
NSString *cellValue = [menuArray objectAtIndex:indexPath.row];
cell.textLabel.text = cellValue;
return cell;
}
I hope someone could help me with it, I'm fairley new to UITableViews and Addressbooks :)
For performance purposes (not to mention animation purposes), UITableView does not automatically update itself whenever the data source changes.
Try adding [myTableView reloadData]; after you add the first and last name to the arrays (or in viewWillAppear:
I'm getting a EXC_BAD_ACCESS crash when switching back and forth between views. I'm having a problem finding the cause of this crash. In the simulator it always goes back to the main.m file and reports the crash in it.
But on my device the EXC_BAD_ACCESS show up on my custom UITableViewCell when I release it in the dealloc method. If I enable NSZombieEnabled my app doesn't crash at all.
Here is the .h file
#import <UIKit/UIKit.h>
#define kWinsAmountTagValue 2 // how many wins you have
#define kWinningsAmountTagValue 3 // how much money you won
#interface MyStatsViewController : UIViewController
<UITableViewDelegate, UITableViewDataSource,
UINavigationBarDelegate, UINavigationControllerDelegate>{
NSArray *list;
UITableView *theTable;
UITableViewCell *theCell;
}
#property (nonatomic, retain) NSArray *list;
#property (nonatomic, retain) IBOutlet UITableView *theTable;
#property (nonatomic, retain) IBOutlet UITableViewCell *theCell;
// dealloc and cleanup
-(void) dealloc;
// misc methods
-(void)loadData;
// demo data
-(NSArray *)tableData;
#end
Here is my .m file
#import "MyStatsViewController.h"
#implementation MyStatsViewController
#synthesize list;
#synthesize theTable;
#synthesize theCell;
#pragma mark - dealloc and cleanup
- (void)didReceiveMemoryWarning
{
// Releases the view if it doesn't have a superview.
[super didReceiveMemoryWarning];
NSLog(#"Memory Warning");
// Release any cached data, images, etc that aren't in use.
}
- (void)viewDidUnload
{
[super viewDidUnload];
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
self.list = nil;
self.theTable = nil;
self.theCell = nil;
}
- (void)dealloc
{
[super dealloc];
[list release];
[theTable release];
[theCell release];
}
#pragma mark - misc methods
-(void) loadData
{
self.list = [self tableData];
}
#pragma mark - View lifecycle
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
}
-(void)viewWillAppear:(BOOL)animated
{
[self loadData];
[theTable reloadData];
}
#pragma mark - Table Data Source Methods
-(NSInteger)tableView:(UITableView *)tableView
numberOfRowsInSection:(NSInteger)section
{
return [list count];
}
-(UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier =#"MyStatsCustomCellIdentifer";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier: CellIdentifier];
NSUInteger row = [indexPath row];
if (cell == nil) {
if (row == [list count] -1) {
cell = [[[UITableViewCell alloc]
initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:CellIdentifier] autorelease];
} else {
NSArray *nib = [[NSBundle mainBundle] loadNibNamed:#"MyStatsCustomCell"
owner:self
options:nil];
if ([nib count] > 0) {
cell = self.theCell;
} else {
NSLog(#"failed to load MyStatsCustomCell");
}
}
}
// Add custom stuff here for rows
//cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
if (row == [list count] -1) {
cell.textLabel.text = [list objectAtIndex:row];
} else {
UILabel *prizeLevel = (UILabel *)[cell viewWithTag:kPrizeLevelTagValue];
prizeLevel.text = [[list objectAtIndex:row] objectForKey:#"prizeLevel"];
UILabel *winsAmount = (UILabel *)[cell viewWithTag:kWinsAmountTagValue];
winsAmount.text = [[list objectAtIndex:row] objectForKey:#"winsAmount"];
UILabel *winningsAmount = (UILabel *)[cell viewWithTag:kWinningsAmountTagValue];
winningsAmount.text = [[list objectAtIndex:row] objectForKey:#"winningsAmount"];
}
//NSLog(#"theCell Retain: %i",[theCell retainCount]);
return cell;
}
#pragma mark - Table View Delegate Methods
-(void)tableView:(UITableView *)tableView
didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[tableView deselectRowAtIndexPath:indexPath animated:YES];
}
#pragma mark - demo data
-(NSArray *)tableData
{
NSArray *prizeLevels = [[NSArray alloc] initWithObjects:
#"6-of-6", #"5-of-6", #"4-of-6",#"3-of-6", nil];
NSArray *winsAmount = [[NSArray alloc] initWithObjects:
#"0", #"0", #"2", #"100", nil];
NSArray *winngingsAmount = [[NSArray alloc] initWithObjects:
#"$0",#"$0", #"$45.50",#"$125.00", nil];
NSMutableArray *myGames = [[[NSMutableArray alloc] init] autorelease];
for (int i = 0; i < [prizeLevels count]; i++) {
NSMutableDictionary *dict = [[NSMutableDictionary alloc] init];
[dict setObject:[prizeLevels objectAtIndex:i] forKey:#"prizeLevel"];
[dict setObject:[winsAmount objectAtIndex:i] forKey:#"winsAmount"];
[dict setObject:[winngingsAmount objectAtIndex:i] forKey:#"winningsAmount"];
[myGames addObject:dict];
[dict release];
}
[prizeLevels release];
[winsAmount release];
[winngingsAmount release];
[myGames addObject:#"Spent: $1250.00"];
return myGames;
}
#end
Any help would be appreciated.
It is a good practice to clean up class's own variables before calling the super's destructor. A lot more details can be found here: Why do I have to call super -dealloc last, and not first?.