saving NSMutable Array Data - iphone

I have a UITableView that is populated using a NSMutableArray . I am using xcode 4.2
the data in the NSMutable array stays in case I switch applications but it gets erased in these two cases :
1-the user switch view and come back .
2-the application is completley closed (i.e. the user double click on the Main button and remove it from the list of running application)
here is the code that I am using
-(NSString *)dataFilePath{
NSString *dataFilePath;
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentationDirectory, NSUserDomainMask, YES);
NSString *documentDirectory = [paths objectAtIndex:0];
dataFilePath = [documentDirectory stringByAppendingPathComponent:#"Test App-Info.plist"];
return dataFilePath;
}
-(void)saveData{
[NSKeyedArchiver archiveRootObject:[data copy] toFile:[self dataFilePath]];
}
- (void)loadData
{
data = [NSKeyedUnarchiver unarchiveObjectWithFile:self.dataFilePath];
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
...
//saving the history
NSArray *archivedArray =[NSKeyedUnarchiver unarchiveObjectWithFile:[self dataFilePath]];
if (archivedArray == nil) {
data = [[NSMutableArray alloc] init];
}
else {
[self loadData];
[mainTableView reloadData];
}
}
Please let me know if I am missing something
Thanks
Edited :
the save data function is loaded in two locations :
1- the app that I am developing scans QR codes , so save data is called in the following function :
- (void) imagePickerController: (UIImagePickerController*) reader
didFinishPickingMediaWithInfo: (NSDictionary*) info
{
....
id<NSFastEnumeration> results =
[info objectForKey: ZBarReaderControllerResults];
ZBarSymbol *symbol = nil;
for(symbol in results){
// EXAMPLE: just grab the first barcode
break;
}
if(!symbol)
return;
// EXAMPLE: do something useful with the barcode data
theBarcodeString = symbol.data;
//adding the string to the list
[data addObject:theBarcodeString];
[self saveData];
[mainTableView reloadData];
[self endText];
stringLabel.text=theBarcodeString;
...
}
it is also called in when the data is edited :
-(IBAction)editTable{
UIBarButtonItem *leftItem;
[mainTableView setEditing:!mainTableView.editing animated:YES];
if (mainTableView.editing) {
leftItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemDone target:self action:#selector(editTable)];
}
else {
leftItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemEdit target:self action:#selector(editTable)];
}
[self saveData];
[mainTableView reloadData];
}

You need to look into the following calls:
applicationDidEnterBackground
applicationWillEnterForeground
applicationDidBecomeActive
applicationWillTerminate
They are all methods of UIApplication. Your needs will dictate which of the above store and restore your data depending on when it should happen.

Related

Populating NSDictionary and NSArrays for Model data

I'm trying to create an NSDictionary full of arrays in the implementation file of my model but my code hasn't worked yet. I want to create arrays that are lists of types of dogs and cats and then add those arrays to a dictionary with keys called DOG and CAT. Here is my code:
#implementation wordDictionary
#synthesize catList = _catList;
#synthesize dogList = _dogList;
#synthesize standardDictionary =_standardDictionary;
- (void)setCatList:(NSMutableArray *)catList
{
self.catList = [NSMutableArray arrayWithObjects:#"lion", #"puma", #"snow leopard", nil];
}
- (void)setDogList:(NSMutableArray *)dogList
{
self.dogList = [NSMutableArray arrayWithObjects:#"pit bull", #"pug", #"chihuahua", nil];
}
-(void)setStandardDictionary:(NSMutableDictionary *)standardDictionary
{
[self.standardDictionary setObject: _catList forKey:#"CAT"];
[self.standardDictionary setObject: _dogList forKey:#"DOG"];
}
- (NSString*)selectKey
{
NSInteger keyCount = [[self.standardDictionary allKeys] count];
NSInteger randomKeyIndex = arc4random() % keyCount;
NSString *randomKey = [[self.standardDictionary allKeys] objectAtIndex:randomKeyIndex];
return randomKey;
}
#end
This code is the model. The model is hooked up to my view controller such that when a user taps a button, the NSString returned from randomKey is displayed in a label on the screen. So the text will read either CAT or DOG. Here's the code for that:
- (IBAction)changeGreeting:(UIButton*)sender {
NSString *chosenKey = [self.dictionary selectKey];
NSString *labelText = [[NSString alloc] initWithFormat:#"%#", chosenKey];
self.label.text = labelText;
}
Unfortunately when I tap the button on the simulator I get an error message saying: Thread 1:EXC_ARITHMETIC (code=EXC_1386_DIV, subcode=0x0) at NSInteger randomKeyIndex = arc4random() % keyCount; and it appears that I'm getting it because neither my NSArray nor my NSDictionary have any objects inside of them.
Does anyone have any idea why my NSArray and NSDictionary haven't been populated?
Thanks very much.
The simple answer is that there isn't any code here that calls the methods to set the arrays or dictionary.
But the real underlying issue is that there are a couple of bad 'patterns' going on here that you should fix:
In your setter methods (setCatList:, setDogList:, setStandardDictionary:) you're not setting the properties in question to the values that are passed in. For example, you should be setting catList to the passed in "catList" variable.
- (void)setCatList:(NSMutableArray *)catList
{
if (_catList != catList) {
[_catList release];
_catList = [catList retain];
}
}
Then you should have some kind of "setup" happening, usually in a method in the view controller like viewDidLoad:
[wordDictionary setCatList:[NSMutableArray arrayWithObjects:#"lion", #"puma", #"snow leopard", nil]];
// and more for the other two setters
Alternately, you can set these default values in the init for the wordDictionary class:
- (id)init {
self = [super init];
if (self) {
[self setCatList:[NSMutableArray arrayWithObjects:#"lion", #"puma", #"snow leopard", nil]];
}
return self;
}
The former is better in most cases, but you may have a good reason to pre-populate your model for all instances of the class.
Assuming you called setCatList:, setDogList: and setStandardDictionary: before. Probably that causing is this :
NSString *chosenKey = [self.dictionary selectKey];
change into this :
NSString *chosenKey = [self selectKey];
UPDATE
I'm trying to make your life easier. no need to create your object if you don't need the most.
- (NSMutableArray*)getCatList
{
return [NSMutableArray arrayWithObjects:#"lion", #"puma", #"snow leopard", nil];
}
- (NSMutableArray*)getDogList
{
return [NSMutableArray arrayWithObjects:#"pit bull", #"pug", #"chihuahua", nil];
}
-(NSMutableDictionary*)getStandardDictionary
{
NSMutableDictionary *standardDictionary = [NSMutableDictionary new];
[standardDictionary setObject:[self getCatList] forKey:#"CAT"];
[standardDictionary setObject:[self getDogList] forKey:#"DOG"];
return [standardDictionary autorelease];
}
- (NSString*)selectKey
{
NSMutableDictionary *standardDictionary = [self getStandardDictionary];
NSInteger keyCount = [[standardDictionary allKeys] count];
NSInteger randomKeyIndex = arc4random() % keyCount;
NSString *randomKey = [[standardDictionary allKeys] objectAtIndex:randomKeyIndex];
return randomKey;
}
- (IBAction)changeGreeting:(UIButton*)sender {
// NSString *chosenKey = [self selectKey];
//NSString *labelText = [[NSString alloc] initWithFormat:#"%#", chosenKey];
self.label.text = [self selectKey]; //no need to convert it to NSString again
}
Two things to consider:
I don't see you calling these:
setCatList:(NSMutableArray*)catList;
setDogList:(NSMutableArray*)dogList;
You use self.catList and self.dogList, but neither of those are synthesized, instead you have beatList and meList synthesized
Change the synthesizes to the catList and dogList, and make sure you call the set list methods, and then you should make some progress.

Wierd behaviour of a singleton object

I'm having really weird situation. I create a singletone object of a class named "Profile like this:
static Profile *currentProfile;
+ (Profile *)currentProfile
{
#synchronized(self)
{
if (currentProfile == nil)
currentProfile = [[Profile alloc] init];
}
return currentProfile;
}
- (id)init
{
self = [super init];
if (self)
{
// Initialization code here.
isChecked = [[[NSUserDefaults standardUserDefaults] objectForKey:#"isChecked"] boolValue];
if (isChecked)
{
NSLog(#"isChecked block is called");
NSData *data = [[NSUserDefaults standardUserDefaults] objectForKey:#"myEncodedObjectKey"];
self = (Profile *) [NSKeyedUnarchiver unarchiveObjectWithData:data];
[self retain];
for (int i = 0; i < self.avatar.count; i++)
[self.avatar replaceObjectAtIndex:i withObject:[UIImage imageWithData:[self.avatar objectAtIndex:i]]];
}
else
{
password = #"";
pfefferID = #"";
email = #"";
avatar = [[NSMutableArray alloc] initWithObjects:
[UIImage imageNamed:#"empty_image.png"],
[UIImage imageNamed:#"empty_image.png"],
[UIImage imageNamed:#"empty_image.png"],
[UIImage imageNamed:#"empty_image.png"],
[UIImage imageNamed:#"empty_image.png"],nil];
isBoy = YES;
friends = [[NSMutableDictionary alloc] init];
rating = 0;
}
}
return self;
}
In init method i check a certain condition stored in NSUserDefaults by using BOOL variable named "isChecked". isChecked is equal to YES and everything works fine. But... i create this Profile object in AppDelegate file like this
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
users = [[NSMutableDictionary alloc] init];
usersForLeaderboardFromServer = [[NSMutableDictionary alloc] init];
listOfFriendsFromServer = [[NSMutableDictionary alloc] init];
currentProfile = [Profile currentProfile];
sessionID = 0;
if (!currentProfile.isChecked)//why????
NSLog(#"not checked");
if (currentProfile.isChecked)
{
[self getUsersForLeaderboardFromServer];
MainMenuView *mainMenu = [[[MainMenuView alloc] init] autorelease];
[self.navigationController pushViewController:mainMenu animated:YES];
}
}
So the same isChecked variable which a moment (far less than a moment actually) ago was equal to YES gets equal to NO when being used in application didFinishLaunchingWithOptions method by accessing it via dot. What's going on? I'm able to handle it but i'm just curious about this situation. Do you know what's wrong with it?
You're reassigning self in init, so you're returning the new object rather than the one you set isChecked on. See this code:
self = (Profile *) [NSKeyedUnarchiver unarchiveObjectWithData:data];
[self retain];
It's slightly awkward to do things like you've got - I would certainly not recommend replacing it in the way you have. For a start, the value you set to the static currentProfile is not being updated when you reassign self so that's still the old one. And also you're not releasing the old self when you reassign.
To fix it you could do something like this:
id newSelf = (Profile *) [NSKeyedUnarchiver unarchiveObjectWithData:data];
newSelf.isChecked = isChecked;
[self release];
self = [newSelf retain];
But I don't really advocate that personally. I suggest you load in the object from your archive and then proceed to update yourself with it rather than reassigning self.

PickerView crashes out EXC_BAD_ACCESS when moved

I have a pickerView, it appears in the Simulator but as soon as I try and scroll it, it crashes EXC_BAD_ACCESS in the main.m file.
I know it is to do with the arrays that I load in from a pList because when I try this with arrays that are initialised in the program it works (see commented out sections), is this something to do with 'nil' at the end of the array? If so how can I see this and how can I add it.
I appreciate any help on this please I'm pulling what's left of my hair out, and I'm fairly new to this...
// Method to define the numberOfComponent in a picker view.
- (NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView
{
return 2;
}
// Method to define the numberOfRows in a component using the array.
- (NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent :(NSInteger)component
{
if (component==0)
{
return [maximumSpeed count];
}
else
{
return[warningTime count];
}
}
//PickerViewController.m
- (NSString *)pickerView:(UIPickerView *)thePickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component
{
NSString *stringToReturn = nil;
switch (component)
{
case 0:
stringToReturn = [maximumSpeed objectAtIndex:row];
break;
case 1:
stringToReturn = [warningTime objectAtIndex:row];
break;
}
return stringToReturn;
}
// Implement viewDidLoad to do additional setup after loading the view, typically from a nib.
- (void)viewDidLoad
{
[super viewDidLoad];
// finding the path and loading the pList as a dictionary into 'data'
NSString *pListFile = [[NSBundle mainBundle] pathForResource:#"PropertyList" ofType:#"plist"];
data =[NSDictionary dictionaryWithContentsOfFile:pListFile];
// get and set up the 2 arrays
maximumSpeed = [data valueForKey:#"MaximumSpeed"];
warningTime = [data valueForKey:#"WarningTime"];
//maximumSpeed =[[NSArray alloc] initWithObjects:#"Running",#"Crying",#"Boring",#"Working",nil];
//warningTime = [[NSArray alloc] initWithObjects: #"Happy", #"Sad" , #"Good", #"joyce",nil];
NSLog(#"%#", maximumSpeed);
NSLog(#"%#", warningTime);
}
(void)viewDidUnload
{
[self setTxt1:nil];
[pickerView release];
pickerView = nil;
[super viewDidUnload];
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
}
- (void)dealloc {
[txt1 release];
[pickerView release];
[warningTime release];
[maximumSpeed release];
[super dealloc];
}
You do not own the object(s) returned by valueForKey, in this case, your arrays. These objects are getting released and you end up with a dangling pointer. Hence, the crash. The problem is here:
maximumSpeed = [data valueForKey:#"MaximumSpeed"];
warningTime = [data valueForKey:#"WarningTime"];
You need to retain them.
maximumSpeed = [[data valueForKey:#"MaximumSpeed"] retain];
warningTime = [[data valueForKey:#"WarningTime"] retain];
The following works because you own the objects you create.
//maximumSpeed =[[NSArray alloc] initWithObjects:#"Running",#"Crying",#"Boring",#"Working",nil];
//warningTime = [[NSArray alloc] initWithObjects: #"Happy", #"Sad" , #"Good", #"joyce",nil];
This also applies to dictionaryWithContentsOfFile:
data =[NSDictionary dictionaryWithContentsOfFile:pListFile];
You can retain (like before) or switch to the alloc-init version:
data = [[NSDictionary dictionaryWithContentsOfFile:pListFile] retain];
// or
data = [[NSDictionary alloc] initWithContentsOfFile:pListFile];
You do not own the objects returned by methods unless the method name begins with "alloc", "new", "copy" or "mutableCopy".
As it has been said already, you could copy the objects (arrays) maximumSpeed and warningTime or, alternatively, you retain and release them.
Talking about releasing ... You are releasing pickerView twice. First in viewDidUnload and second in dealloc. It may actually work without a crash because you assign nil to it after the first release and therefore the second release should be processed without a crash anyway.
However, that indicates that you should be more careful about your memory management, retain-release-pairs in particular.
Why don't you track the zombies in the instrumemts application? You start it in xcode4 with cmd-i.
In most cases that gives some useful hint on where to have a detailed look on missing retains (or copies).

Dealing with editable items in a filtered UITable with an NSMutableArray copy

I have a UITable with a datasource that is set to a 'copy' of the original data. I use this copy to displayed filtered results (either 'All' or only those that are 'checked' with a UISwitch in each row). My logic for doing the filtering is here:
-(void)filterItems {
[tableData removeAllObjects];
if (checkedOrNotSwitch.selectedSegmentIndex == 0) {
[tableData addObjectsFromArray:self.defaultChecklistItemsArray];
} else {
for (NSMutableDictionary *sectionDict in self.defaultChecklistItemsArray) {
NSMutableArray *newItemsArray = [[NSMutableArray alloc] init];
[newItemsArray removeAllObjects];
for (NSMutableDictionary *itemDict in [sectionDict objectForKey:#"categoryItems"]) {
if ([[itemDict objectForKey:#"isComplete"] boolValue]) {
[newItemsArray addObject:itemDict];
}
}
if ([newItemsArray count] > 0) {
NSMutableDictionary *newSectionDict = [[NSMutableDictionary alloc] initWithDictionary:sectionDict];
[newSectionDict setObject:newItemsArray forKey:#"categoryItems"];
[tableData addObject:newSectionDict];
[newSectionDict release];
}
}
}
[checklistTable reloadData];
}
The filtering itself now works correctly. In my custom cell, each row has a UISwitch. The switch runs this function when its changed:
-(IBAction) switchValueChanged{
NSIndexPath *indexPath = [(UITableView *)self.superview indexPathForCell: self];
[self.parentController updateCompletedStatusAtIndexPath:indexPath toStatus:isCompleted.on];
}
The function above is in the class for the tableviewcell itself. The function I call in the superview is this:
-(void)updateCompletedStatusAtIndexPath:(NSIndexPath *)indexPath toStatus:(BOOL)status{
NSUInteger section = [indexPath section];
NSUInteger row = [indexPath row];
NSMutableDictionary *currentsection = [[NSMutableDictionary alloc] initWithDictionary:[tableData objectAtIndex:section]];
NSMutableArray *itemsArray = [[NSMutableArray alloc] initWithArray:[currentsection objectForKey:#"categoryItems"] copyItems:YES];
NSMutableDictionary *tempDict = [[NSMutableDictionary alloc] initWithDictionary:[itemsArray objectAtIndex:row]];
NSLog(#"BOOL = %#\n", (status ? #"YES" : #"NO"));
[tempDict setValue:[NSNumber numberWithBool:status] forKey:#"isComplete"];
[itemsArray replaceObjectAtIndex:row withObject:tempDict];
[currentsection setValue:itemsArray forKey:#"categoryItems"];
[tableData replaceObjectAtIndex:section withObject:currentsection];
[tempDict release];
[itemsArray release];
[currentsection release];
[checklistTable reloadData];
}
Before I implemented the filtering and used the logic above on self.defaultChecklistItemsArray directly, it worked and saved the data when the switch was flipped.
Now when I first enter the app, it loads the array of data from nsuserdefaults. I navigate to the view with the table and it displays the data correctly there with the UISwitches all in the correct position given the data (some on, some off). When I tap one of the switches, then click the segmentedcontrol that does the filtering, the data reverts back to the state it was loaded in, implying that the flipping of the switch did not actually effect the data at all (even though I don't think I did a deep copy anywhere here so I figured it should be doing the right thing). Any suggestions?

MFMailComposeViewController problem

This problem is probably not specific to MFMailComposeViewController, but that is where I am having the problem...
I am building the NSString
"myEmailString" for the messageBody of
the MFMailComposeViewController and
storing it in an iVar before
displaying the
MFMailComposeViewController as a
modal view controller.
I pass the string into the MFMailComposeViewController, then present it as a modal view controller.
When the modal view controller is dismissed, my iVar becomes invalid,
and the app crashes when I release the emailString iVar in dealloc
Code below, what am I doing wrong?
-(void)buildEmailMessage {
int mySection;
int myRow;
NSString *buildString = [NSString stringWithFormat:#"<b><p>Ten Essentials Check List</b><br />%#</p>", [myList valueForKey:#"listName"]];
for (mySection = 0; mySection < [[fetchedResultsController sections] count]; mySection ++) {
NSString *sectionName = [NSString stringWithFormat:#"<p><b>%# Group</b></p><ul>", [[[fetchedResultsController sections] objectAtIndex:mySection] name]];
buildString = [buildString stringByAppendingString:sectionName];
id <NSFetchedResultsSectionInfo> sectionInfo = [[fetchedResultsController sections] objectAtIndex:mySection];
for (myRow = 0; myRow < [sectionInfo numberOfObjects]; myRow ++) {
// Get the managedObject
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:myRow inSection:mySection];
NSManagedObject *managedObject = [fetchedResultsController objectAtIndexPath:indexPath];
//Get the related Item object
Item *item = [managedObject valueForKey:#"item"];
NSString *itemName = [NSString stringWithFormat:#"<li>%#</li>", item.itemName];
buildString = [buildString stringByAppendingString:itemName];
}
buildString = [buildString stringByAppendingString:#"</ul>"];
}
myEmailString = [NSString stringWithString:buildString];
NSLog(#"email string = :\n%#", myEmailString);
[self showPicker];
}
#pragma mark -
#pragma mark Send Mail
-(void)showPicker {
// This code can run on devices running iPhone OS 2.0 or later
// The MFMailComposeViewController class is only available in iPhone OS 3.0 or later.
// So, we must verify the existence of the above class and provide a workaround for devices running
// earlier versions of the iPhone OS.
// We display an email composition interface if MFMailComposeViewController exists and the device can send emails.
// We launch the Mail application on the device, otherwise.
NSLog(#"Checking OS for MFMailComposeViewController");
Class mailClass = (NSClassFromString(#"MFMailComposeViewController"));
if (mailClass != nil)
{
// We must always check whether the current device is configured for sending emails
if ([mailClass canSendMail])
{
[self displayComposerSheet];
}
else
{
[self launchMailAppOnDevice];
}
}
else
{
[self launchMailAppOnDevice];
}
}
// Displays an email composition interface inside the application. Populates all the Mail fields.
-(void)displayComposerSheet {
MFMailComposeViewController *picker = [[MFMailComposeViewController alloc] init];
picker.mailComposeDelegate = self;
picker.navigationBar.barStyle = UIBarStyleBlack;
[picker setSubject:#"Here is your gear check list!"];
// Attach an image to the email
NSString *path = [[NSBundle mainBundle] pathForResource:#"Checkmark_icon" ofType:#"png"];
NSData *myData = [NSData dataWithContentsOfFile:path];
[picker addAttachmentData:myData mimeType:#"image/png" fileName:#"Checkmark_icon"];
// Fill out the email body text
//***** NOTE: This is where I pass the value from my iVar *****
// into the MFMailComposeViewController
//
NSString *emailBody = [NSString stringWithString:myEmailString];
[picker setMessageBody:emailBody isHTML:YES];
NSLog (#"DIsplaying Composer Sheet");
[self presentModalViewController:picker animated:YES];
[picker release];
}
// Dismisses the email composition interface when users tap Cancel or Send. Proceeds to update the message field with the result of the operation.
- (void)mailComposeController:(MFMailComposeViewController*)controller didFinishWithResult:(MFMailComposeResult)result error:(NSError*)error {
//message.hidden = NO;
// Notifies users about errors associated with the interface
switch (result)
{
case MFMailComposeResultCancelled:
NSLog (#"Result: canceled");
break;
case MFMailComposeResultSaved:
NSLog (#"Result: saved");
break;
case MFMailComposeResultSent:
NSLog (#"Result: sent");
break;
case MFMailComposeResultFailed:
NSLog (#"Result: failed");
break;
default:
NSLog (#"Result: not sent");
break;
}
[self dismissModalViewControllerAnimated:YES];
// ***** NOTE: Line below was added to fix the invalid iVar problem *****
myEmailString = #"";
}
#pragma mark -
#pragma mark Workaround
// Launches the Mail application on the device.
-(void)launchMailAppOnDevice {
NSString *recipients = #"mailto:first#example.com?cc=second#example.com,third#example.com&subject=Here is your gear check list!";
NSString *body = myEmailString;
NSString *email = [NSString stringWithFormat:#"%#%#", recipients, body];
email = [email stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:email]];
}
- (void)dealloc {
[managedObjectContext release];
[fetchedResultsController release];
[tableview release];
[myList release];
[myEmailString release];
[super dealloc];
}
how is your ivar declared? is it declared as a property? in any case, it is not automatically retained for you.
Either you need to do
myEmailString = [[NSString stringWithString:buildString] retain];
or
self.myEmailString = [NSString stringWithString:buildString];
if you have myEmailString declared as
#property (nonatomic, retain) NSString *myEmailString
Think about it: if all ivars were automatically retained for you, then how would you have a variable that you didn't want to retain? That's why it doesn't work that way.
when you are creating the myEmail string in buildEmailMessage you are never retaining the string. Thus after leaving the function it is autoreleased. Your retain count then when dealloc is called will be 0, which will cause the crash. If you want to keep the variable you will need to have the line as follows
myEmailString = [[NSString stringWithString:buildString] retain];
then you can call [myEmailString release] safely
stringWithString: creates a new string and autoreleases it before returning it to you. Unless you retain the returned string, you don't need to release it in your dealloc method.
You should be retaining your string before storing it in your iVar:
myEmailString = [[NSString stringWithString:buildString] retain];
It becomes invalid without this due to it being autoreleased later during the execution of your program. This will also ensure it's still allocated when your destructor is called, preventing release crashing.