I want to create a plist in code and add more "records" from user input to it. I have created a plist, and I can write the user input, but I can't add data to my plist. Every time, it saves the last input and keeps only one "record". This is the code:
-(void) createPlistFile {
manager = [NSFileManager defaultManager];
filepath = #"/Users/agnostos_el/Downloads/PhoneBook/PhoneBook/Epafes.txt";
if ( [manager fileExistsAtPath:filepath] == NO )
{
NSLog(#"Το Αρχειο Δεν Υπαρχει Το δημειουργω");
[[NSFileManager defaultManager]createFileAtPath:filepath contents:nil attributes:nil];
}
}
-(void) openPlistFile {
NSArray *path = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
if( [path count] > 0 ){
pListFile = [[path objectAtIndex:0] stringByAppendingPathComponent:filepath];
NSDictionary *pListDict = [[NSDictionary alloc]initWithContentsOfFile:filepath];
if ( [pListDict count] <= 0 )
{
}
[self createPlistFile];
}
}
- (void) times
{
filepath = #"/Users/agnostos_el/Downloads/PhoneBook/PhoneBook/Epafes.txt";
stoixeia = [NSArray arrayWithObjects:onoma.stringValue, poli.stringValue, odos.stringValue, per.stringValue, tk.stringValue, xora.stringValue,kin.stringValue, kin1.stringValue, kin2.stringValue, kat.stringValue, erg.stringValue, fax.stringValue, email.stringValue, email1.stringValue, email2.stringValue, pros.stringValue, sim.stringValue, nil];
eponimos = epitheto.stringValue;
NSMutableDictionary *atomo = [NSMutableDictionary dictionary];
innerDict = [NSDictionary dictionaryWithObjects:
[NSArray arrayWithObjects: eponimos, stoixeia, nil]
forKeys:[NSArray arrayWithObjects:#"eponimo", #"stoixeia", nil]];
[atomo setObject:innerDict forKey:eponimos];
id plist = [NSPropertyListSerialization dataFromPropertyList:(id)atomo
format:NSPropertyListXMLFormat_v1_0 errorDescription:nil];
record = [[NSData alloc]initWithData:plist];
[record writeToFile:filepath atomically:YES];
}
- (void) eggrafi
{
[self openPlistFile];
[self times];
}
Any suggestions? Thanks.
You are not passing the file contents to createFileAtPath:contents:attributes::
[[NSFileManager defaultManager]createFileAtPath:filepath contents:nil attributes:nil];
Related
- (void)readFolder:(NSString *)str :(NSMutableDictionary *)dict {
NSArray *appFolderContents = [[NSArray alloc] init];
appFolderContents = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:str error:nil];
for (NSString *app in appFolderContents) {
if ([app containsString:#".app"])
{
NSString *appName = [[app lastPathComponent] stringByDeletingPathExtension];
NSString *appPath = [NSString stringWithFormat:#"%#/%#", str, app];
NSString *appBundle = [[NSBundle bundleWithPath:appPath] bundleIdentifier];
// NSLog(#"%# -- %#", appPath, appBundle);
NSArray *jumboTron = [NSArray arrayWithObjects:appName, appPath, appBundle, nil];
[dict setObject:jumboTron forKey:appName];
}
}
}
//This searches for apps
- (void)getAPPList {
NSMutableDictionary *myDict = [[NSMutableDictionary alloc] init];
[self readFolder:#"/Applications" :myDict];
[self readFolder:#"/Applications/Utilities" :myDict];
[self readFolder:#"/System/Library/CoreServices" :myDict];
[self readFolder:#"/Volumes/Macintosh HD/Applications" :myDict ];
// Volumes not named 'Macintosh HD' doesn't work, I'm trying to make it work
[self readFolder:#"/Volumes/*/Applications" :myDict ];
//Some apps are stored in the user's Application folder instead of the main one
[self readFolder:[NSString stringWithFormat:#"%#/Applications", NSHomeDirectory()] :myDict];
//Sometimes people keep apps in Downloads
[self readFolder:[NSString stringWithFormat:#"%#/Downloads", NSHomeDirectory()] :myDict];
//Some apps are stored in the user's Library/Application Support sometimes
[self readFolder:[NSString stringWithFormat:#"%#/Library/Application Support", NSHomeDirectory()] :myDict];
I'm trying to make line 26 ([self readFolder:#"/Volumes/*/Applications" :myDict ]) search all volumes, instead of only searching a volume with a matching/specific name. How can I do this?
I'm using Xcode 9.2
something like this should do the trick (untested)
NSArray *keys = [NSArray arrayWithObjects:NSURLVolumeURLKey, NSURLIsVolumeKey, nil];
NSArray *volumeUrls = [[NSFileManager defaultManager] mountedVolumeURLsIncludingResourceValuesForKeys:keys options:NSVolumeEnumerationSkipHiddenVolumes];
for (NSURL *volumeUrl in volumeUrls)
{
BOOL mayBeBootVolume = NO;
NSString* pathToVolume = [volumeUrl path];
[self readFolder: [pathToVolume stringByAppendingString: #"/Applications"];
}
I test to see if a directory is saving and it doesn't seem that it is.
Here is what I have, it's essentially creating a list of which files have been uploaded to Dropbox. DropboxList is declared in the header file and then synchronized.
int i = 0;
DropboxList = [[NSMutableDictionary alloc]init];
do {
[DropboxList setObject:#"NO" forKey:[NSNumber numberWithInt:i]];
i++;
} while (i < sortedFiles.count);
NSLog(#"dropbox list is %#", DropboxList);
NSArray *dropBoxPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *dropBoxDocumentsDirectory = [dropBoxPaths objectAtIndex:0];
NSString *dropBoxDataPath = [dropBoxDocumentsDirectory stringByAppendingPathComponent:#"/DropboxUploads"];
if (![[NSFileManager defaultManager] fileExistsAtPath:dropBoxDataPath]) {
[[NSFileManager defaultManager] createDirectoryAtPath:dropBoxDataPath withIntermediateDirectories:NO attributes:nil error:nil];
}
NSString *filePath = [dropBoxDataPath stringByAppendingPathComponent:#"dropboxList.out"];
[DropboxList writeToFile:filePath atomically:YES];
NSMutableDictionary *newDictionary = [NSMutableDictionary dictionaryWithContentsOfFile:filePath];
NSLog(#"newDictionary list is %#", newDictionary);
Here is my console:
dropbox list is {
0 = NO;
3 = NO;
2 = NO;
1 = NO;
4 = NO;
}
newDictionary list is (null)
I've tried alloc init for the newDictionary before writing and I get the same result. Any ideas?
The problem is with the following line
[DropboxList setObject:#"NO" forKey:[NSNumber numberWithInt:i]];
DropboxList writeToFile only works with the valid property list. For a NSMutableDictionary to be a valid property list object, its keys should be string type instead of NSNumber.
Solution
[DropboxList setObject:#"NO" forKey:[NSString stringWithFormat:#"%d",i]]];
Also, make use of the writeToFile return parameter to validate.
BOOL isWritten = [DropboxList writeToFile:filePath atomically:YES];
if (isWritten)
{
NSMutableDictionary *newDictionary = [NSMutableDictionary dictionaryWithContentsOfFile:filePath];
NSLog(#"newDictionary list is %#", newDictionary);
{
else
{
NSLog(#"Something went wrong");
}
Okay, so my problem was that I had NSNumbers as the keys, which doesn't work. I made the keys strings, and we're golden.
If i enumerate an array i get
<myArray: 0x71b26b0>
<myArray: 0x71b2830>
<myArray: 0x71b2900>
I could take it that myData is behind the pointers listed, but if I wanted to explicitly see (log) the contents at each address, how to do that?
I have tried the &myData to no avail
--
for the benefit of uchuugaka:
-(void)loadObservedItems{
NSString *path = [self observationFilePath];
if ([[NSFileManager defaultManager] fileExistsAtPath:path]) {
NSData *data = [[NSData alloc] initWithContentsOfFile:path];
NSKeyedUnarchiver *unarchiver = [[NSKeyedUnarchiver alloc] initForReadingWithData:data];
myArray = [unarchiver decodeObjectForKey:#"ObserveKey"];
[unarchiver finishDecoding];
} else {
myArray = [[NSMutableArray alloc] initWithCapacity:10];
}
NSLog(#" %#",myArray);
}
Add to MyClass.m:
-(NSString*)description {
NSMutableDictionary* descDict = [NSMutableDictionary dictionary];
[descDict addObject:someField forKey:#"someField"]
[descDict addObject:anotherField forKey:#"anotherField"];
[descDict addObject:yetAnotherField forKey:#"yetAnotherField"];
return [descDict description];
}
Then just use NSLog(#"myObject is %#", myObject);. Just like the big guys.
Slightly more sophisticated is to (within the method) pre-pend your class name and the object address to the result string, but that's usually unnecessary for simple debugging.
But I think you can do that like this:
return [NSString stringWithFormat:#"%# : %#", [super description], [descDict description]];
hi i tried to add values(book id,page number,notes) from NSdictionary to Plist but each time the new value replacing the previous one?but i need all values in plist my code for adding dictionary to plist is
NSString *bid=#"95";
NSString *pnum=#"12";
userNotes=[[NSMutableDictionary alloc]init];
[userNotes setValue:userNotesTextview.text forKey:#"notes"];
[userNotes setValue:bid forKey:#"bookid"];
[userNotes setValue:pnum forKey:#"pagenumber"];
userNotesView.hidden=YES;
_background.hidden = YES;
userNotesTextview.text=#"";
[self savingMetaData];
NSMutableArray *notes=[[NSMutableArray alloc]init];
[notes addObject:userNotes];
NSMutableDictionary *final=[[NSMutableDictionary alloc]init];
[final setValue:notes forKey:#"usernotes"];
[final writeToFile:metaDataPath atomically:YES];
and my plist look like
how can i solve this problem
Fetch the existing array from the plist as below, but first make sure you have copied you plist to Documents directory or, to some writable folder as below
NSFileManager *fileManager=[NSFileManager defaultManager];
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory , NSUserDomainMask, YES);
NSString *docPath=[[paths objectAtIndex:0] stringByAppendingString:#"yourplist.plist"];
BOOL fileExists = [fileManager fileExistsAtPath: docPath];
NSError *error = nil;
if(!fileExists)
{
NSString *strSourcePath = [[NSBundle mainBundle] pathForResource:#"yourplist" ofType:#"plist"];
[fileManager copyItemAtPath:strSourcePath toPath:docPath error:&error];
}
NSString *path = docPath;
NSMutableDictionary *plistdictionary = [[NSMutableDictionary alloc]initWithContentsOfFile:path];
NSMutableArray *notes=[plistdictionary objectForKey:#"usernotes"];
if(notes==nil){
notes=[[NSMutableArray alloc] init];
}
NSString *bid=#"95";
NSString *pnum=#"12";
userNotes=[[NSMutableDictionary alloc]init];
[userNotes setValue:userNotesTextview.text forKey:#"notes"];
[userNotes setValue:bid forKey:#"bookid"];
[userNotes setValue:pnum forKey:#"pagenumber"];
[notes addObject:userNotes];
then finally
NSMutableDictionary *final=[[NSMutableDictionary alloc]init];
[final setValue:notes forKey:#"usernotes"];
[final writeToFile:docPath atomically:YES];
Note: You cannot write anything in MainBundle, so better to copy your plist to Documents directory and use from there..
because plist can store value with unique key only. if you try to save value with same key it will replace old one with new value. so always save new value with new key (eg. item0, item1, item3 etc.)
following line will store two usernote with key #"usernotes1" and #"usernotes2" respectively
[final setValue:notes forKey:#"usernotes1"];
[final setValue:notes forKey:#"usernotes2"];
Plist structure looks like this
You can create a UserNote model class.
#define kBookID #"bookid"
#define kPageNumber #"pageNumber"
#define kNotes #"notes"
#interface UserNote : NSObject
#property (nonatomic, copy) NSString *bookID;
#property (nonatomic, copy) NSString *pageNumber;
#property (nonatomic, copy) NSString *notes;
- (id)initWithDictionary:(NSDictionary *)dictionary;
+ (NSArray *)savedUserNotes;
- (void)save;
#end
Initialize
- (id)initWithDictionary:(NSDictionary *)dictionary
{
self = [super init];
if (self)
{
self.bookID = dictionary[kBookID];
self.pageNumber = dictionary[kPageNumber];
self.notes = dictionary[kNotes];
}
return self;
}
Find the document path of plist file in documents directory. If the plist file is not there create a new one and return the path.
+ (NSString *)userNotesDocumentPath
{
NSString *documentsPath = [[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0] stringByAppendingPathComponent:#"UserNotes.plist"];
NSFileManager *fileManger = [NSFileManager defaultManager];
if (![fileManger fileExistsAtPath:documentsPath])
{
NSString *bundleResourcePath = [[NSBundle mainBundle]pathForResource:#"UserNotes" ofType:#"plist"];
NSArray *userNotes = [NSArray arrayWithContentsOfFile:bundleResourcePath];
[userNotes writeToFile:documentsPath atomically:YES];
}
return documentsPath;
}
Fetches all saved usernotes from plist file.
+ (NSArray *)savedUserNotes
{
NSString *documentsPath = [self userNotesDocumentPath];
NSArray *savedNotes = [NSArray arrayWithContentsOfFile:documentsPath];
NSMutableArray *savedUserNotes = [#[] mutableCopy];
for (NSDictionary *dict in savedNotes) {
UserNote *note = [[UserNote alloc]initWithDictionary:dict];
[savedUserNotes addObject:note];
}
return savedUserNotes;
}
Saves a usenote to plist
- (NSDictionary *)userNoteDictionary
{
return #{kBookID:self.bookID,kPageNumber:self.pageNumber,kNotes:self.notes};
}
- (void)saveUserNotesToPlist:(NSArray *)userNotes
{
NSMutableArray *mutableUserNotes = [#[] mutableCopy];
for (UserNote *note in userNotes) {
NSDictionary *dict = [note userNoteDictionary];
[mutableUserNotes addObject:dict];
}
NSString *documentsPath = [UserNote userNotesDocumentPath];
[mutableUserNotes writeToFile:documentsPath atomically:YES];
}
#pragma mark - Save
- (void)save
{
NSMutableArray *savedNotes = [[UserNote savedUserNotes] mutableCopy];
[savedNotes addObject:self];
[self saveUserNotesToPlist:savedNotes];
}
In you viewController where user makes a note
- (IBAction)saveUserNoteButtonPressed:(UIButton *)button
{
UserNote *note = [UserNote new];
note.bookID = #"95";
note.pageNumber = #"12";
note.notes = self.userNotesTextview.text;
[note save];
}
Demo Source Code
I am uncertain of how memory is managed in my particular case...
I have two methods:
+(NSMutableDictionary *)loadPlist: (NSString*) name
andErrorDesc: (NSString*) errorDesc
andFormat: (NSPropertyListFormat*) format
andplistPath: (NSMutableString*) plistPath
{
NSString * destPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
destPath = [destPath stringByAppendingPathComponent:
[NSString stringWithFormat:#"%#.plist", name]];
if (![[NSFileManager defaultManager] fileExistsAtPath:destPath])
{
[[NSFileManager defaultManager] copyItemAtPath:[[NSBundle mainBundle] pathForResource:name ofType:#"plist"] toPath:destPath error:nil];
}
plistPath = [NSMutableString stringWithString:[destPath copy]];
NSData * plistXML =
[[NSFileManager defaultManager] contentsAtPath:plistPath];
NSLog(#"AFTER plistPath: \n%#",plistPath);
return
(NSMutableDictionary *)[NSPropertyListSerialization
propertyListFromData:plistXML
mutabilityOption:NSPropertyListMutableContainersAndLeaves
format:format
errorDescription:&errorDesc];
}
+(bool)writeToCache:(NSString*) data andField: (NSString*) field
{
NSString * errorDesc = nil;
NSPropertyListFormat format;
NSMutableString * plistPath;
NSMutableDictionary * temp = [BPUtils loadPlist:#"cache" andErrorDesc:errorDesc andFormat:&format andplistPath:plistPath];
if (!temp)
{
NSLog(#"Error reading plist: %#, format: %d", errorDesc, format);
return false;
}
NSMutableArray * arr = [temp objectForKey:field];
[arr addObject:data];
NSLog(#"path: %#",plistPath);
// Write to plist
bool res = [temp writeToFile:plistPath atomically:YES];
NSLog(#"RES: %d", res);
return true;
}
The problem is that the bottom method that sends in "plistPath" to the above method retrives a null plistPath after the above method has set it. Why and how can I fix this?
NSLog(#"path: %#",plistPath);
in the bottom method shows null, why?
I use ARC. Also "destPath" is set and shows the correct path.
I believe you could be a bit confused here.
You are creating plistPath in the bottom method. And then you pass plistPath into
[BPUtils loadPlist:#"cache" andErrorDesc:errorDesc andFormat:&format andplistPath:plistPath];
but plistPath is NULL
NSMutableString * plistPath; // Is NULL
But once it has been passed in the local plistPath takes over.
+(NSMutableDictionary *)loadPlist: (NSString*) name
andErrorDesc: (NSString*) errorDesc
andFormat: (NSPropertyListFormat*) format
andplistPath: (NSMutableString*) plistPath // Notice the local plistPath variable. This is the one you are playing with in this method.
At this point you are setting plistPath but remember it is still just a local variable and not an instance variable. So the button method will never know about it being set, as far as the button method is concerned it is still NULL
plistPath = [NSMutableString stringWithString:[destPath copy]];
So whatever you set in plistPath in the top method will not get passed back to the bottom method, think of the top plistPath as being deallocated when the method does the return.
So the plistPath in the bottom method will remain NULL
So try this instead SOLUTION
static NSMutableString *yourNewStringforPlistPath; //This will be NULL
+(NSMutableDictionary *)loadPlist: (NSString*) name
andErrorDesc: (NSString*) errorDesc
andFormat: (NSPropertyListFormat*) format
andplistPath: (NSMutableString*) plistPath
{
NSString * destPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
destPath = [destPath stringByAppendingPathComponent:
[NSString stringWithFormat:#"%#.plist", name]];
if (![[NSFileManager defaultManager] fileExistsAtPath:destPath])
{
[[NSFileManager defaultManager] copyItemAtPath:[[NSBundle mainBundle] pathForResource:name ofType:#"plist"] toPath:destPath error:nil];
}
yourNewStringforPlistPath = [NSMutableString stringWithString:[destPath copy]];
NSData * plistXML =
[[NSFileManager defaultManager] contentsAtPath:yourNewStringforPlistPath];
NSLog(#"AFTER plistPath: \n%#",yourNewStringforPlistPath);
return
(NSMutableDictionary *)[NSPropertyListSerialization
propertyListFromData:plistXML
mutabilityOption:NSPropertyListMutableContainersAndLeaves
format:format
errorDescription:&errorDesc];
}
+(bool)writeToCache:(NSString*) data andField: (NSString*) field
{
NSString * errorDesc = nil;
NSPropertyListFormat format;
NSMutableDictionary * temp = [BPUtils loadPlist:#"cache" andErrorDesc:errorDesc andFormat:&format andplistPath:[NSNull null]]; // As this is already NULL you don't really need to pass yourNewStringforPlistPath in unless in the future this value can be set before this.
if (!temp)
{
NSLog(#"Error reading plist: %#, format: %d", errorDesc, format);
return false;
}
NSMutableArray * arr = [temp objectForKey:field];
[arr addObject:data];
NSLog(#"path: %#",yourNewStringforPlistPath);
// Write to plist
bool res = [temp writeToFile:yourNewStringforPlistPath atomically:YES];
NSLog(#"RES: %d", res);
return true;
}