NSMutableArray always return null - objective-c

My problem is when I read content of plist file in an NSMutableArray always return null
NSString *resourceDocPath = [[NSString alloc] initWithString:[[NSBundle mainBundle]bundlePath]] ;
// Create the new dictionary that will be inserted into the plist.
NSMutableDictionary *nameDictionary = [NSMutableDictionary dictionary];
[nameDictionary setValue:#"walid" forKey:#"id"];
[nameDictionary setValue:#"555 W 1st St" forKey:#"lien"];
NSString *r = [NSString stringWithFormat:#"%#/download.plist", resourceDocPath];
NSLog(#"%#",r);
// Open the plist from the filesystem.
NSMutableArray *plist = [NSMutableArray arrayWithContentsOfFile:r];
NSLog(#"%#",plist);
if (plist == NULL)
{
plist = [NSMutableArray array];
}
[plist addObject:nameDictionary];
NSLog(#"%#",plist);
[plist writeToFile:r atomically:YES];
when I look in the plist file I found the data that I insert only one
can you help me please?

You're trying to access the application bundle rather than the documents directory, which can be accessed via NSString *documentsDirectory = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
NSString *sourcePath = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:#"Populator"];. The bundle cannot be modified, so the created array is never saved, hence why it is never loaded.

First you should not check for plist == null but check for plist == nil
Second searching for the download file should be changed into the following:
NSURL *url = [[NSBundle mainBundle] URLForResource:#"download" withExtension:#"plist"];
NSMutableArray *plist = [NSMutableArray arrayWithContentsOfURL:url];
Third:
I do not think a file with the extension of plist will return an Array.
It will probably represent an dictionary. Try creating an NSMutableDictionary instead of an array.

Related

NSMutableArray addObjects NSString

I have an problem with NSString and NSMutableArray
I Have:
NSString *msgID;
NSMutableArray *mArray;
and msgID string is an unique ID for every message and it changes it self every time when you receive a new message.
and now i want to save those IDS into NSMutableArray to put them inside plist file.
but the problem is when i do like the following
a = [[NSMutableArray alloc] init];
[a addObject:msgID];
it save only the first ID not the rest of theme
Example if the output ID is 65465465151 and you received new message after one second with ID 2123545445 the NSMutableArray save only the first output.
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<array>
<string>65465465151</string>
</array>
</plist>
how can I make NSMutableArray add all outputs or strings which already output using one NSString ?
Here is my code
NSString *msgID = [viewcontroller.messageID substringFromIndex:[viewcontroller.messageID length] - 21];
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *path = [documentsDirectory stringByAppendingPathComponent:#"msgIDs.plist"];
NSFileManager *fileManager = [NSFileManager defaultManager];
NSMutableArray *mArray;
if (![fileManager fileExistsAtPath:path]) {
path = [documentsDirectory stringByAppendingPathComponent: [NSString stringWithFormat: #"msgIDs.plist"] ];
}
if ([fileManager fileExistsAtPath:path]) {
mArray = [[NSMutableArray alloc] init];
[mArray addObject:msgID];
} else {
// If the file doesn’t exist, create an empty dictionary
mArray = [[NSMutableArray alloc] init];
}
[mArray writeToFile:path atomically:YES];
If that's your code, and it's all in one block like that and not spread over several methods, in several different loops, then you're creating a new instance of mArray every time you go through the code block, and, as a result, at most there will be one entry in the array.
Your code looks OK, provided you are not trying to create the array in a loop repeatedly. Each addObject will enlarge the array by one. Make sure you write your plist file after the array is populated the way you expect. Make sure any old plist file is overwritten.

How to edit elements in plist file

I have a Settings.plist and I want to edit some values in this file.
My function to edit/writing is:
- (void) setParamWithName: (NSString*) Name withValue: (NSString*) Value {
// get paths from root direcory
NSArray *paths = NSSearchPathForDirectoriesInDomains (NSDocumentDirectory, NSUserDomainMask, YES);
// get documents path
NSString *documentsPath = [paths objectAtIndex:0];
// get the path to plist file
NSString *plistPath = [documentsPath stringByAppendingPathComponent:#"Settings.plist"];
// check to see if Data.plist exists in documents
if (![[NSFileManager defaultManager] fileExistsAtPath:plistPath])
{
// if not in documents, get property list from main bundle
plistPath = [[NSBundle mainBundle] pathForResource:#"Settings" ofType:#"plist"];
}
// read property list into memory as an NSData object
NSData *plistXML = [[NSFileManager defaultManager] contentsAtPath:plistPath];
NSString *errorDesc = nil;
NSPropertyListFormat format;
// convert static property list into dictionary object
NSDictionary *temp = (NSDictionary *)[NSPropertyListSerialization propertyListFromData:plistXML mutabilityOption:NSPropertyListMutableContainersAndLeaves format:&format errorDescription:&errorDesc];
if (!temp)
{
NSLog(#"Error reading plist: %#, format: %d", errorDesc, format);
}
// checking if element exists, if yes overwriting
// if element not exists adding new element
[temp writeToFile:plistPath atomically:YES];
}
This function read and write (with te same values) Settings.plist.
I do not have any idea (my knowledge about objective-c is not enough) how to add new element or edit existing element. Can anyone help mi with this issue?
I think it's easier as you think.
Once you got the path of the file read it into a NSDictionary. Make a mutable copy of that dictionary with mutableCopy and NSMutableDictionary.
Now edit that mutable dictionary as you like (add s.th., remove s.th., edit s.th. and so on).
Now that you're done you can write it back to the old path as you did with temp.
Your main problem is that you're not working with a mutable version of that dicitionary. It'd make your life much easier.

Read from file.Plist Returns Null

Program that Creates multiple Plist's Paths for Different information.
But only one path is not working.
(i think "writeToFile" is the problem)
code:
-(NSString *) createPath:(NSString *)withFileName
{
NSArray *paths =NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask,
YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *path = [documentsDirectory stringByAppendingPathComponent:withFileName];
return path;
}
Path
NSLog = /var/mobile/Applications/02CABC0A-6B5B-4097-A9D1-4336BE8230B7/Documents/MessagesDB.plist
&
-(void) messagesDbFlush
{
// save it to the file for persistency
NSString *messagesDB_Path = [self createPath:_fileMessagesDB];
[_messagesDB writeToFile:messagesDB_Path atomically:YES];
NSMutableArray *ReturnsInfo = [[NSMutableArray alloc ]initWithContentsOfFile:messagesDB_Path];
NSLog(#"ReturnsInfo is : %#", ReturnsInfo);
}
"ReturnsInfo" Array is Null :/
Anyone please help?
I once had the same error.
1) Check the name of the plist in the directory listing to match your coded one
2) Check Project settings, manually delete the pre-existing plist from the "Build Settings" > "Copy Bundle Resources", and drag drop from the list.
3) Select the plist in directory listing, check Utilities sidebar, check Identity & Type > Location as valid
4) If you deleted the app's "default" plist aka bundle identifier, add copy build phase, choose destination, choose pref folder as absolut path check "copy only when installing"
This solved my returning null.
And if all fails on the bundle identifier, you can always copy the plist to pref folder by code:
NSString *path = [#"~/Library/Preferences/com.MyCompany.MyApp.plist" stringByExpandingTildeInPath];
BOOL PrefsExist=[[NSFileManager defaultManager] fileExistsAtPath:path];
NSString *copyPrefsPath = [#"~/Library/Preferences/com.MyCompany.MyApp.plist" stringByExpandingTildeInPath];
NSFileManager *fileManager = [NSFileManager defaultManager];
if (PrefsExist == 0)
{
// Copy the plist to prefs folder (one-time event)
NSString *tessdataPath = [[NSBundle mainBundle] pathForResource:#"com.MyCompany.MyApp" ofType:#"plist"];
[fileManager copyItemAtPath:tessdataPath toPath:path error:&error];
} else
{
// Read/Write the values from plist
}
i have stored following array with 5 objects in it, its working fine on my side, try it
NSMutableArray *array = [[NSMutableArray alloc] initWithCapacity:5];
for(int i=0;i<5;i++)
[array addObject:#"This is Demo String, You can write your own String here"];
NSString *_fileMessagesDB = #"MessagesDB.plist";
// save it to the file for persistency
NSString *messagesDB_Path = [self createPath:_fileMessagesDB];
[array writeToFile:messagesDB_Path atomically:YES];
NSMutableArray *ReturnsInfo = [[NSMutableArray alloc ]initWithContentsOfFile:messagesDB_Path];
NSLog(#"ReturnsInfo is : %#", ReturnsInfo);

How to write data in .plist?

I'm trying to save some comments in a plist, that's OK cause its just a prototype. The problem is that i can read from plist but when I try to write and read after that, it throws an "array out of bounds" exception. I can't figure it out what I'm doing wrong here.
NSString *filePath = [[NSBundle mainBundle] pathForResource:#"Comments" ofType:#"plist"];
NSMutableArray *plistArray = [[NSMutableArray alloc] initWithContentsOfFile:filePath];
NSMutableDictionary *newComment = [NSMutableDictionary dictionary];
[newComment setValue:commentTitle.text forKey:#"title"];
[newComment setValue:comment forKey:#"comment"];
[plistArray addObject:newComment];
[plistArray writeToFile:filePath atomically:NO];
That works fine, then i try to read:
NSString *filePath = [[NSBundle mainBundle] pathForResource:#"Comments" ofType:#"plist"];
NSMutableArray *plistArray = [[NSMutableArray alloc] initWithContentsOfFile:filePath];
NSMutableDictionary *dictionary = (NSMutableDictionary *) [plistArray objectAtIndex:0];
NSLog(#"%#", [dictionary objectForKey:#"title"]);
And it throws the exception.
If I add the item manually to the plist, it works fine, i guess it means that my reading code its fine.
Could it be the structure of my plist?
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<array>
</array>
</plist>
* Terminating app due to uncaught exception 'NSRangeException', reason: '-[__NSCFArray objectAtIndex:]: index (1) beyond bounds (1)'
I added the "description" to the array before writing to the plist. If i use the following code:
NSString *aDocumentsDirectory = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
// NSString *aFilePath = [NSString stringWithFormat:#"%#/Comments.plist", aDocumentsDirectory];
//
// NSMutableArray *plistArray = [[NSMutableArray alloc] initWithContentsOfFile:aFilePath];
The return is (null)
But if i use:
NSString *filePath = [[NSBundle mainBundle] pathForResource:#"Comments" ofType:#"plist"];
NSMutableArray *plistArray = [[NSMutableArray alloc] initWithContentsOfFile:filePath];
i can see the contents of the array, and its all working properly.
The problem is: In both ways i cant write to the file, it keeps returning "NO". And i already checked the permissions
You are trying to write the file into mainBundle. Definitely not possible.
You will have to write the plist file to Documents or Application Support folder of the app.
Create File Path in Documents Directory :
NSString *aDocumentsDirectory = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
NSString *aFilePath = [NSString stringWithFormat:#"%#/Comments.plist", aDocumentsDirectory];
Write to FilePath
[plistArray writeToFile:aFilePath atomically:YES];
Read From FilePath
NSMutableArray *plistArray = [[NSMutableArray alloc] initWithContentsOfFile:aFilePath];
I see two problems with your code:
(May or may not be a problem). If the file does not exist initially, the initWithContentsOfFile: selector will return nil, causing the rest of your code to be no-ops.
(Probably the cause). You may not write to the bundle resources directory. Store your file in the Documents or Caches directory instead.
To locate your documents directory, use something like this:
- (NSString*) pathForDocument:(NSString*)documentName {
NSArray *documentDirectories = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
if(documentDirectories.count < 1) return nil;
return [[documentDirectories objectAtIndex:0] stringByAppendingPathComponent:documentName];
}
First of all, why are you writing a file into your bundle?
Then, to address your problem, check if you actually did write the file.
if ([plistArray writeToFile:filePath atomically:NO])
NSLog (#"Written");
else
NSLog (#"Not Written");
Also, log your array when you're read it using -(void)description to check the contents of the dictionary.
Edit
As you said that you're not writing to your plist. For now, just create a test plist on your desktop.
NSString *testPath = [[NSString stringWithString:#"~/Desktop/Comments.plist"] stringByExpandingTildeInPath];
if ([plistArray writeToFile:testPath atomically:NO])
NSLog (#"Written");
else
NSLog (#"Not Written");
If that still returns Not Written, then there's something wrong with your dictionary. Which I doubt because it's just strings (Though they could be placeholders for asking your question on stackoverflow. The docs states that the classes in the dictionary must be of NSData, NSDate, NSNumber, NSString, NSArray, or NSDictionary). If that says written though, I'm guessing it doesn't write to your bundle because of permissions, which then you have to change your plist location to somewhere else other than your bundle, which I highly recommend.
If you only put one item in the array, you should obviously use index 0 instead of 1 when reading from it:
NSMutableDictionary *dictionary = (NSMutableDictionary *) [plistArray objectAtIndex:0];

can't save plist. path is not writable

I'm saving a lot of informations in a plist. This one is by standart in my mainBundle.
this is my method to load the path and the data from the plist. if the file in the "application support" folder doesn't exist, i'm copying it from the mainBundle to there.
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
self.plistPath = [documentsDirectory stringByAppendingPathComponent:[NSString stringWithFormat:#"%#.plist",plistName]];
NSFileManager *fileManager = [NSFileManager defaultManager];
if (![fileManager fileExistsAtPath: self.plistPath])
{
NSString *pathInBundle = [[NSBundle mainBundle] pathForResource:plistName ofType:#"plist"];
self.plist = [NSMutableDictionary dictionaryWithContentsOfFile:pathInBundle];
NSLog(#"plist doesnt exist");
}
else {
self.plist = [NSMutableDictionary dictionaryWithContentsOfFile:self.plistPath];
NSLog(#"plist exist");
}
NSLog(#"plist path: %#",self.plistPath);
if i add the following lines at the end, there's only NO the answer:
if([fileManager isWritableFileAtPath:self.plistPath]) NSLog(#"YES");
else NSLog(#"NO");
after all, i tried to save with [self.plist writeToFile:self.plistPath atomically:YES];, which is also not working.
sorry for answering so late - i had a lot of other stuff to do. back to my problem: i only get the error, when i try to add a new entry to my dictionary (plist). editing is no problem. i think the problem is, how i try to add the entry. my code looks like:
NSMutableDictionary *updateDict = [[self.plist objectForKey:#"comments"]mutableCopy];
NSMutableDictionary *tmpDict = [[[NSMutableDictionary alloc]init]autorelease];
[tmpDict setObject:comment forKey:#"comment"];
[tmpDict setObject:author forKey:#"author"];
[tmpDict setObject:car forKey:#"car"];
[tmpDict setObject:part forKey:#"part"];
[tmpDict setObject:date forKey:#"date"];
[updateDict setObject:tmpDict forKey:[NSNumber numberWithInt:[updateDict count]+1]];
[self.plist setObject:updateDict forKey:#"comments"];
if([self.plist writeToFile:self.plistPath atomically:YES]) {
return YES;
}
else {
return NO;
}
self.plist is my local copy of the file at plistPath. the structure of my plist looks like: https://img.skitch.com/20111026-tcjxp9ha4up8ggtfjy7ucgqcqe.png
hope this helps
Ok, so that's not the Documents directory and iOS doesn't have an Application Support directory created in the sandbox by default, which is why you can't write.
You can either change your method call to look-up the real documents directory:
NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
Or, after you get the path to the Application Support directory, you must check to see if it exists already and if not, create it.
please go through the previous post which shows the different way to copy the plist from mainBundle. Use [fileManager copyItemAtPath:defaultDBPath toPath:writableDBPath error:&error]; method instead.
Did you find answer? if not, you need to change this line:
[updateDict setObject:tmpDict forKey:[NSNumber numberWithInt:[updateDict count]+1]];
to
[updateDict setObject:tmpDict forKey:[NSString stringWithFormat:#"%d",[updateDict count]+1]];
Key name is string, not object.