Reputation: 175
I am attempting to display an NSMutableArray
of an object I created to a UITableView
. Everything displays, except when I try to scroll the table view and then I get an EXC_BAD_ACCESS.
Here's my object:
.h file
@interface EmailAddressClass : NSObject {
@public NSString * fullName;
@public NSString * myEmailAddress;
BOOL isSelected;
}
@property (nonatomic, retain) NSString * fullName;
@property (nonatomic, retain) NSString * myEmailAddress;
- (void) setFullname:(NSString *)pMyName;
- (void) setMyEmailAddress:(NSString *)pEmailAddress;
- (void) setIsSelected:(BOOL)pSelectedFlag;
- (BOOL) getIsSelected;
- (NSString *) getFullname;
- (NSString *)getMyEmailAddress;
@end
.m file
#import "EmailAddressClass.h"
@implementation EmailAddressClass
@synthesize fullName;
@synthesize myEmailAddress;
- (void) setFullname:(NSString *)pMyName{
fullName = pMyName;
}
- (void) setMyEmailAddress:(NSString *)pEmailAddress{
myEmailAddress = pEmailAddress;
}
- (NSString *) getFullname{
return fullName;
}
- (NSString *)getMyEmailAddress{
return myEmailAddress;
}
- (void) setIsSelected:(BOOL)pSelectedFlag{
isSelected = pSelectedFlag;
}
- (BOOL) getIsSelected{
return isSelected;
}
@end
Straightforward enough; just a small class that holds name and email address as NSString
s.
This is how I populate the array from address book with names and email addresses
- (NSMutableArray*)getAllEmailAddress{
CFMutableArrayRef myMutablePeople = [self getSortedAddressBook];
NSMutableArray *allEmails = [[NSMutableArray alloc] initWithCapacity:CFArrayGetCount(myMutablePeople)];
for (CFIndex i = 0; i < CFArrayGetCount(myMutablePeople); i++) {
ABRecordRef person = CFArrayGetValueAtIndex(myMutablePeople, i);
ABMultiValueRef emails = ABRecordCopyValue(person, kABPersonEmailProperty);
NSString *firstName = (NSString *)ABRecordCopyValue(person, kABPersonFirstNameProperty);
NSString *lastName = (NSString *) ABRecordCopyValue(person, kABPersonLastNameProperty);
for (CFIndex j=0; j < ABMultiValueGetCount(emails); j++) {
NSString* email = (NSString*)ABMultiValueCopyValueAtIndex(emails, j);
EmailAddressClass * anEmailPerson = [EmailAddressClass alloc];
[anEmailPerson setIsSelected:YES];
[anEmailPerson setMyEmailAddress:email];
if ((firstName) && (lastName) != nil){
[anEmailPerson setFullname:[NSString stringWithFormat:@"%@ %@", firstName, lastName]];
} else if ((firstName != nil) && (lastName == nil)){
[anEmailPerson setFullname:[NSString stringWithFormat:@"%@", firstName]];
} else if ((firstName ==nil) && (lastName != nil)){
[anEmailPerson setFullname:[NSString stringWithFormat:@"%@", lastName]];
} else {
[anEmailPerson setFullname:[NSString stringWithFormat:@"%@", email]];
}
[allEmails addObject:anEmailPerson];
[email release];
[anEmailPerson release];
}
CFRelease(emails);
}
CFRelease(myMutablePeople);
// CFRelease(people);
return allEmails;
}
Everything is working up to this point; the array returns the correct number of people, with their email address.
This is how I populate the table view
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = @"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:CellIdentifier] autorelease];
}
thisPerson = (EmailAddressClass *)[allEmails objectAtIndex:indexPath.row];
cell.textLabel.text = [thisPerson getFullname];
return cell;
}
What am I missing?
snipped of of EmailListViewController.h
#import "EmailAddressClass.h"
@interface EmailListViewController : UITableViewController {
NSMutableArray *allEmails;
EmailAddressClass * thisPerson;
}
@property (nonatomic, retain) NSMutableArray *allEmails;
@property (nonatomic, retain) EmailAddressClass * thisPerson;
@synthesize allEmails, thisPerson; both gets synthesized in the .m file
on Viewdidload in EmailListViewController.m
- (void)viewDidLoad
{
[super viewDidLoad];
self.navigationController.toolbarHidden=NO;
// Uncomment the following line to preserve selection between presentations.
// self.clearsSelectionOnViewWillAppear = NO;
self.tableView.rowHeight = ROW_HEIGHT;
// Uncomment the following line to display an Edit button in the navigation bar for this view controller.
// self.navigationItem.rightBarButtonItem = self.editButtonItem;
allEmails = [[MsgController sharedMsgController] getAllEmailAddress];
/*NSLog(@"There are : %d number of emails", [allEmails count]);
for (EmailAddressClass *email in allEmails)
{
NSLog(@"%@ : %@", [email getFullname],[email getMyEmailAddress]) ;
}
*/
}
the console output shows correct names and emails in the array
Upvotes: 1
Views: 216
Reputation: 39296
When you're looping and setting, you create the string by calling stringWithFormat. Since that's not alloc, copy, mutableCopy, it's autoreleased.
Then you assign it, hold it but do not retain it:
In the loop:
// this is autoreleased
[anEmailPerson setFullname:[NSString stringWithFormat:@"%@ %@", firstName, lastName]];
In the class:
// you're holding a reference to something that's about to go poof
- (void) setFullname:(NSString *)pMyName{
fullName = pMyName;
}
I would recommend either retaining it or declaring it as a property and synthesizing it:
@property (retain, atomic) NSString *fullName;
then in .m
@synthesize fullName;
I would also recommend that your getAllEmailAddresses function does an autorelease - the caller of the function can choose to retain it. Have your allEmails property retain that after your function autoreleases. The memory management rules say that if it doesn't start with alloc, copy or immutableCopy, it's autoreleased and it's up to the caller to retain.
Read the apple memory management guide - good read.
Specifically, on the second page, read the rules.
Upvotes: 1