In my existing app, I have about 450 very small PDF files that are lyrics to songs. They are all stored in a directory called (appropriately) "ThePDFs". The downside with this is that every time I want to add a new set of lyrics, I have to release an update to the app. What I'd love to do is use something like the Parse server to point toward PDFs stored online, and allow the user to select those and add them to their existing list.
However, I don't think it is possible or allowed for me to take an outside PDF and write them into that directory called "ThePDFs"? If it's not allowed, what would be a good way to accomplish this, in such a way that all the songs are in one list? I know I could download them into a documents folder for the app, but then I have songs in multiple locations, and accessing them all in one tableview might be more difficult. I suppose at first launch of the app, I could have all the PDFs copy from the bundled section into the documents directory, and search to it from that?
I know I have a lot of options, I'm just curious if there's something I'm missing. UPDATE So, I'm trying to do the first option of leaving PDFs where they are, and make a PLIST that would have an item with each song's name, along with the location for where it is in the file system. Then, when new songs are added, it would do the same, and I could read from the PLIST file to get all songs and be able to open them, no matter where they are. My issue right now is getting the initial PLIST set up, and the logic behind what I would do for each subsequent addition. The issue I get is
NSDictionary initWithObjects:forKeys:]: count of objects (0) differs from count of keys (1)'
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *path = [documentsDirectory stringByAppendingPathComponent:@"mastersonglist.plist"];
NSFileManager *fileManager = [NSFileManager defaultManager];
if (![fileManager fileExistsAtPath: path]) {
path = [documentsDirectory stringByAppendingPathComponent: [NSString stringWithFormat:@"mastersonglist.plist"] ];
}
NSError *error = nil;
NSMutableDictionary *data;
if ([fileManager fileExistsAtPath: path]) {
data = [[NSMutableDictionary alloc] initWithContentsOfFile: path];
}
else {
// If the file doesn’t exist, create an empty dictionary
data = [[NSMutableDictionary alloc] init];
}
NSBundle *bundle = [NSBundle mainBundle];
self.files = [bundle pathsForResourcesOfType:@"pdf" inDirectory:@"thepdfpowerpoints"];
NSMutableArray *names = [NSMutableArray arrayWithCapacity:[self.files count]];
for (NSString *path in self.files) {
[names addObject:[[path lastPathComponent] stringByDeletingPathExtension]];
}
for (NSString *test in names) {
// [data setObject:names forKey:@"thename"];
// [data writeToFile:path atomically:YES];
NSDictionary *innerDict;
NSLog(@"NAMES%@", names);
innerDict = [NSDictionary dictionaryWithObjects:
[NSArray arrayWithObjects: names, path, nil]
forKeys:[NSArray arrayWithObjects:@"Names", @"Path", nil]];
NSLog(@"DICT%@", innerDict);
NSMutableDictionary *plistdictionary = [[NSMutableDictionary alloc]initWithContentsOfFile:path];
NSMutableArray *notes=[plistdictionary objectForKey:@"Questions"];
//NSLog(@"QUESTION %@", innerDict);
[notes addObject:innerDict];
NSLog(@"NOTES %@", notes);
NSDictionary *outerDict = [NSDictionary dictionaryWithObjects:
[NSArray arrayWithObjects: notes, nil]
forKeys:[NSArray arrayWithObjects:@"Questions", nil]];
id plist = [NSPropertyListSerialization dataFromPropertyList:(id)outerDict
format:NSPropertyListXMLFormat_v1_0 errorDescription:&error];
[plist writeToFile:path atomically:YES];
}
CodePudding user response:
First, you're correct, you cannot add files to the app bundle at run-time.
So, various ways to approach this, depending on what functionality you want to provide to the user.
First, you could:
- include the existing PDFs in your app bundle
- check a remote server for new PDFs on launch
- download the new PDFs into a local app folder
generating a data list from both locations to display in a single table would really be a pretty straight-forward and not-at-all complex task.
Second, you could:
- include NO PDFs in your app bundle
- check a remote server for new PDFs on launch (on first launch they'd all be new)
- download the PDFs (on a background thread, of course) into a local app folder
Now you only need to manage the files in one location.
Third, you could:
- include NO PDFs in your app bundle
- check a remote server for the list of available PDFs on launch
- retrieve the PDFs on-demand when the user selects them
- optionally "cache" them locally - so only retrieve if the PDF has not already been selected / downloaded
Edit
You don't really need to know the file locations...
I don't know what information you have associated with each PDF file, so, to simplify, let's assume you're displaying a list of PDF file names (no other data).
The general idea could be:
- get the list of PDF files in the bundle
- append the list of PDF files in the downloads folder
- sort the full list alphabetically
- user selects a PDF
- does file
downloadsPath/filename.pdf
exist?- Yes? load it
- No? load it from bundle
- does file
Same principal if you have some sort of data file - .plist, csv, json, whatever - that would have maybe filename, song title, artist, date, etc.
- load the data for the PDF files included in the bundle
- append the data for the PDF files in the downloads folder
- sort the full list alphabetically
- user selects a song
- does file
downloadsPath/filename.pdf
exist?- Yes? load it
- No? load it from bundle
- does file
No need to track the file location in your data -- just find it when you want to load it.