I have an addToFavourites function, which is causing an EXC_BAD_ACCESS error.
Basically, I have the Favourites View Controller with a list of all the favourites which the user has added previously, now when clicking on one of the favourites, it pushes the view to a detailViewController, this works fine. On the detail view controller, I have an add to favourites button, this button changes to a remove from favourites if it detects that the key already exists in the addToFavourites dictionary. The problem occurs when the user accesses this detailViewController from the favourites page and also from the main page which lists all the detailViews. They are able to do this as I have a tab bar.
So say I am in the detailView accessed through the favourites page, the favourites button has "remove from favourites", this is correct. But then say I click the remove from favourites button, the button changes to "add to favourites" and removes it from the dictionary. All working fine so far. Now when I switch over to the same detailView, but this time accessed from a different tab on the tab bar, firstly the favourites button still reads "remove from favourites" and when I click this button the first time, it changes to "add to favourites", then when I click it again, I get this EXC_BAD_ACCESS error.
Here is the addToFavouritesFunction:
- (IBAction)addToFavourites:(id)sender {
NSString *type = [[NSUserDefaults standardUserDefaults]objectForKey:#"type"];
if(type == #"v") {
NSString *area = [[NSUserDefaults standardUserDefaults]objectForKey:#"area"];
NSString *ID1 = [[NSUserDefaults standardUserDefaults]objectForKey:#"ID1"];
if([[addToFavouritesDictionary allKeys] containsObject:ID1]) {
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *filePath = [documentsDirectory stringByAppendingPathComponent:#"/SavedDict.data"];
[addToFavouritesDictionary removeObjectForKey:ID1];
[favouritesButton setTitle:#"+ Favourites" forState:(UIControlState)UIControlStateNormal];
[addToFavouritesDictionary writeToFile:filePath atomically: YES];
NSLog(#"New Dictionary: %#", addToFavouritesDictionary);
} else {
NSString *ID1 = [[NSUserDefaults standardUserDefaults]objectForKey:#"ID1"];
[addToFavouritesDictionary setObject:Name forKey:ID1];
[favouritesButton setTitle:#"- Favourites" forState:(UIControlState)UIControlStateNormal];
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *filePath = [documentsDirectory stringByAppendingPathComponent:#"/SavedDict.data"];
[addToFavouritesDictionary writeToFile:filePath atomically: YES];
NSLog(#"Mutable Dictionary: %#", addToFavouritesDictionary);
//[addToFavouritesDictionary release];
}
} else {
//NSString *area = [[NSUserDefaults standardUserDefaults]objectForKey:#"area"];
NSString *ID2 = [[NSUserDefaults standardUserDefaults]objectForKey:#"ID2"];
if([[addToFavouritesDictionary allKeys] containsObject:ID2]) {
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *filePath = [documentsDirectory stringByAppendingPathComponent:#"/SavedDict.data"];
[addToFavouritesDictionary removeObjectForKey:ID2];
[favouritesButton setTitle:#"+ Favourites" forState:(UIControlState)UIControlStateNormal];
[addToFavouritesDictionary writeToFile:filePath atomically: YES];
NSLog(#"Dictionary: %#", addToFavouritesDictionary);
} else {
NSString *ID2 = [[NSUserDefaults standardUserDefaults]objectForKey:#"ID2"];
[addToFavouritesDictionary setObject:Name forKey:ID2];
[favouritesButton setTitle:#"- Favourites" forState:(UIControlState)UIControlStateNormal];
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *filePath = [documentsDirectory stringByAppendingPathComponent:#"/SavedDict.data"];
[addToFavouritesDictionary writeToFile:filePath atomically: YES];
NSLog(#"Mutable Dictionary: %#", addToFavouritesDictionary);
}
}
}
Thanks for any help!
Check with debugger whether it shows crashing line exactly ...and set breakpoint after that to check for value
Well...either your addToFavouritesDictionary object or your Name object has been deallocated. How are you creating these objects? Either you are releasing them before you should, or you haven't retained them in the first place.
Objective-C Memory Management
You should probably not be using the line:
if(type == #"v") {
What you are doing here is comparing the pointer for the variable type to the pointer for the string #"v". Instead, you should use a method that compares the contents of the string:
if ([type isEqualToString:#"v") {
EDIT
The easiest way to keep your titles the same would be to store the text in NSUserDefaults. You could do something like below whenever the button is pressed:
// For "Add to Favorites"
[[NSUserDefaults standardUserDefaults] setObject:#"+ Favorites" forKey:#"ButtonState"];
// For "Remove from Favorites"
[[NSUserDefaults standardUserDefaults] setObject:#"- Favorites" forKey:#"ButtonState"];
Then you would execute something like this when the view loads:
[favoritesButton setTitle:(NSString*)[[NSUserDefaults standardUserDefaults] objectForKey:#"ButtonState"] forState:UIControlStateNormal];
Related
is there a possibility to check for an object in an array by name.
At some point in my app I need to access the plist and pull information stored under an object which I found by its name.
The reason I need to do this is because I don't have the integer number under which where the object is placed in my array.
I have started the usual procedure but i'm not getting anywhere. Maybe its just getting a little too late for me....
This is how my plist looks
Array
Dictionary
title ...
text ...
ect ...
Dictionary
title ...
text ...
ect ...
Dictionary
title ...
text ...
ect ...
My code so far isn't helping at all. I'm definitely doing something wrong.
-(NSString*)nameFromPlist:(NSString*)name {
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *writableDBPath = [documentsDirectory stringByAppendingPathComponent:#"Orte.plist"];
_regionArray = [NSArray arrayWithContentsOfFile:writableDBPath];
NSString *string = [[NSString alloc]init];
for(NSDictionary *dict in _regionArray) {
string = [[dict objectForKey:name] valueForKey:#"title"];
}
return [NSString stringWithFormat:#"%#",string];
}
My string is just returning null.
Any ideas anyone?
Thanks a lot!
ANSWER:
Here is the code for everyone:
-(NSString*)nameFromPlist:(NSString*)name {
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *tmpFileName = [[NSString alloc] initWithFormat:#"Orte.plist"];
NSString *path = [documentsDirectory stringByAppendingPathComponent:tmpFileName];
NSString *string;
NSMutableArray *array = [NSMutableArray arrayWithContentsOfFile:path];
NSDictionary *dict = [[NSDictionary alloc] init];
NSString *title;
for (int i=0; i<[array count]; i++) {
dict = [array objectAtIndex:i];
title = [dict valueForKey:#"title"];
if([title isEqualToString:name]) {
string = [dict valueForKey:#"title"];
NSLog(#"Titel: %#", string);
}
}
return [NSString stringWithFormat:#"%#",string];
}
Thank a lot everyone!
First you don't need to alloc the NSString, 'cause you'll get a different one from valueForKey.
Then if I understood right what you want to get a better code may be something that make use of NSPredicate or the block-based indexOfObjectPassingTest. Both iterate across the array and perform a test on the elements to get you the matching elements (or the index of them).
NSString* plistPath = [[NSBundle bundleForClass:[self class]] pathForResource:#"<PlistFileName>" ofType:#"plist"];
NSArray *array = [[NSArray alloc] initWithContentsOfFile:plistPath];
NSMutableArray* titles = [[NSMutableArray alloc] init];
for (NSDictionary* d in array)
[titles addObject:[d objectForKey:#"title"]];
NSLog(#"Object found at index %i", [a indexOfObject:#"<Your object name>"]);
Make sure you're testing against NSNotFound for failure to locate, and not (say) 0.
i know that kind of noob problem but it killing me for 2 days now
i have the following code
albumsVC.discList = [[NSMutableArray alloc]init];
for(id song in songs){
if([self checkIfAllFilesExist:[song objectForKey:#"fileName"]]){
[albumsVC.discList addObject:song];
}
}
and
-(BOOL)checkIfAllFilesExist: (NSString *) theFilename {
BOOL exist;
NSArray *documentPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentDir = [documentPaths objectAtIndex:0];
docPath = [ documentDir stringByAppendingPathComponent:[NSString stringWithFormat:#"%#.mp3",theFilename]];
NSFileManager *fileManager = [NSFileManager defaultManager];
exist = [fileManager fileExistsAtPath:docPath];
docPath = nil;
docPath = [[NSString alloc] init];
if(!exist){
return NO;
}
return YES;
}
but it crashes after five loops (i don't know why five ? ) and it tells me that message sent to deallocated instance 0x87cdc10
on the line of
docPath = [ documentDir stringByAppendingPathComponent:[NSString stringWithFormat:#"%#.mp3",theFilename]];
where docPath is NSString in the header created as nonatomic and retain ..
i can't get the problem can you help me ?
-(BOOL)checkIfAllFilesExist: (NSString *) theFilename creates memory leak.
Replace it with below code:
-(BOOL)checkIfAllFilesExist: (NSString *) theFilename {
BOOL exist;
NSArray *documentPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentDir = [documentPaths objectAtIndex:0];
self.docPath = [ documentDir stringByAppendingPathComponent:[NSString stringWithFormat:#"%#.mp3",theFilename]];
NSFileManager *fileManager = [NSFileManager defaultManager];
exist = [fileManager fileExistsAtPath:docPath];
if(!exist){
return NO;
}
return YES;
}
Assuming that you have docPath property in your .h file with nonatomic, retain.
since you say it is always crashes at the fifth iteration of the loop, check the bject which comes by looping.
I mean to say , check the theFilename. Try printing the 'song' dictionary to make sure you have something in fileName key.
Also use Apurv code.
i think the title says all. I use some example code i found here but the file will not be created.
- (id)init {
[[NSBundle mainBundle] loadNibNamed:#"PadContent" owner:self options:nil];
if ([[NSFileManager defaultManager] fileExistsAtPath:[self filePathOfBookmarks]]) {
bookmarks = [[NSMutableDictionary alloc]
initWithContentsOfFile:[self filePathOfBookmarks]];
} else {
bookmarks = [[NSMutableDictionary alloc] init];
NSLog(#"file does not exist");
}
return self;
}
- (void)addBookmark:(id)sender{
[bookmarks setObject:[dataInstance chapter] forKey:[[dataInstance chapter]title]];
[bookmarks setObject:[dataInstance chapter] forKey:#"test"];
NSLog(#"count: %d", [bookmarks count]);
NSLog([self filePathOfBookmarks]);
[bookmarks writeToFile:[self filePathOfBookmarks] atomically:YES];
}
- (NSString *) filePathOfBookmarks {
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *docDirectory = [paths objectAtIndex:0];
return [docDirectory stringByAppendingPathComponent:#"bookmarks"];
}
What's in your dictionary? There are only certain base objects that can be written out and read back without any additional work on your part. If your dictionary includes a custom object that you defined, you'll need to use another mechanism to write and read back the data, such a an NSArchiver. I am guessing that whatever [dataInstance chapter] yields is not among these basic object types.
See the documentation for NSDictionary's writeToFile:atomically: for the data types that can be read and written automatically. Also look at NSArchiver and the NSCoding protocol.
I am trying to save an NSMutableArray containing text to a plist file using this code:
- (IBAction)saveDoc:(id)sender
{
NSString *typedText = typingArea.text;
NSMutableArray *totalFiles = [[NSMutableArray alloc] initWithObjects:typedText, nil];
NSLog(#"Created: %#", totalFiles);
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *path = [documentsDirectory stringByAppendingPathComponent:#"savedFiles.plist"];
NSLog(#"Found Path: %#", path);
//[totalFiles addObject:typedText];
[totalFiles writeToFile:path atomically:YES];
NSLog(#"File Written: %# to: %#", totalFiles, path);
[totalFiles release];
NSLog(#"Released: %#", totalFiles);
}
All of the NSLogs return appropriate values as expected. I use this code to crate a new NSMutableArray with the contents of the plist:
- (void)viewDidLoad {
file = [[NSBundle mainBundle] pathForResource:#"savedFiles" ofType:#"plist"];
NSLog(#"Got Path: %#", file);
array = [NSMutableArray arrayWithContentsOfFile:file];
NSLog(#"Loaded Array into new array: %#", array);
//UIAlertView *alert = [[[UIAlertView alloc] initWithTitle:#"fdsfasdf" message:[dic objectForKey:#"item1"] delegate:self cancelButtonTitle:#"ldfghjfd" otherButtonTitles:nil] autorelease];
//[alert show];
[super viewDidLoad];
// Uncomment the following line to display an Edit button in the navigation bar for this view controller.
//self.navigationItem.rightBarButtonItem = self.editButtonItem;
}
The NSLogs in this code come back with a slightly different path than the first one returned with. It also said the array is (null)
How should I load the contents from a plist file?
Thanks in advance,
Tate
Try initialising your array first:
array = [[NSMutableArray alloc] initWithContentsOfFile:file];
I'm stumped or just not finding info I need, I have an object that I want to save in an array when they select "saveDataround" button, however I can't seem to figure out how to populate the object with the text "Round": I'm getting an "Expected identifier" and "Expected , ;" errors on the first and second lines of code. Thanks in advance.
[NSString *roundChoice = [NSString stringWithFormat:#"Round"];
self.round.text = roundChoice;]
- (IBAction)saveDataround {
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *recipient = [NSString stringWithFormat:#"%#/arrayChoiceRound", documentsDirectory];
NSMutableArray *array = [[NSMutableArray alloc] init];
[array addObject:round.text];
[array writeToFile:recipient atomically:NO];
}
Where are the first two lines of code implemented? What are they supposed to do?
Here's how I would modify the above code without more info:
// remove "[" from start of line & no need to use stringWithFormat here
NSString *roundChoice = #"Round";
// remove "]" from end of line
self.round.text = roundChoice;
- (IBAction)saveDataround {
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
// use stringByAppendingPathComponent here
NSString *recipient = [documentsDirectory stringByAppendingPathComponent:#"arrayChoiceRound"];
NSMutableArray *array = [[NSMutableArray alloc] init];
// use self here (not required)
[array addObject:self.round.text];
[array writeToFile:recipient atomically:NO];
// release the array
[array release];
}