将文件写入 iOS App Bundle,还是显示 2 个目录的内容?
Write Files into iOS App Bundle, or Show 2 directory's content?
在我现有的应用程序中,我有大约 450 个非常小的 PDF 文件,它们是歌曲的歌词。它们都存储在一个名为(适当地)“ThePDFs”的目录中。这样做的缺点是每次我想添加一组新歌词时,我都必须发布应用程序更新。我想做的是使用 Parse 服务器之类的东西指向在线存储的 PDF,并允许用户 select 这些并将它们添加到他们现有的列表中。
但是,我认为我不可能或不允许我使用外部 PDF 并将它们写入名为“ThePDFs”的目录中?如果不允许,以所有歌曲都在一个列表中的方式实现此目的的好方法是什么?我知道我可以将它们下载到应用程序的文档文件夹中,但是我在多个位置都有歌曲,并且在一个 tableview 中访问它们可能会更加困难。我想在第一次启动该应用程序时,我可以将所有 PDF 从捆绑部分复制到文档目录中,然后从中搜索它?
我知道我有很多选择,我只是想知道我是否遗漏了什么。
更新
所以,我正在尝试第一个选项,将 PDF 保留在原处,并制作一个 PLIST,其中包含每首歌曲的名称以及它在文件系统中的位置。然后,当添加新歌曲时,它会做同样的事情,我可以从 PLIST 文件中读取以获取所有歌曲并能够打开它们,无论它们在哪里。我现在的问题是设置初始 PLIST,以及我为每个后续添加所做的操作背后的逻辑。我得到的问题是
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];
}
首先,您是对的,您不能将文件添加到位于 run-time 的应用程序包中。
因此,有多种方法可以解决此问题,具体取决于您要为用户提供的功能。
首先,您可以:
- 在您的应用程序包中包含现有的 PDF
- 在启动时检查远程服务器是否有新的 PDF
- 将新的 PDF 下载到本地应用程序文件夹中
从两个位置生成数据列表以在单个 table 中显示确实是一项相当 straight-forward 和 not-at-all 的复杂任务。
其次,您可以:
- 在您的应用程序包中包含 NO 个 PDF
- 在启动时检查远程服务器是否有新的 PDF(首次启动时它们都是新的)
- 将 PDF 下载(当然是在后台线程上)到本地应用文件夹
现在您只需要在一个位置管理文件。
第三,你可以:
- 在您的应用程序包中包含 NO 个 PDF
- 在启动时检查远程服务器的可用 PDF 列表
- 在用户选择时检索 PDF on-demand
- 可选择在本地“缓存”它们 - 因此仅在尚未选择/下载 PDF 时才检索
编辑
您真的不需要知道文件位置...
我不知道您有哪些与每个 PDF 文件关联的信息,因此,为简化起见,我们假设您正在显示 PDF 文件名列表(没有其他数据)。
大体思路可以是:
- 获取捆绑包中的 PDF 文件列表
- 在下载文件夹中附加 PDF 文件列表
- 按字母顺序对完整列表进行排序
- 用户选择了一个 PDF
- 文件
downloadsPath/filename.pdf
是否存在?
- 是吗?加载它
- 没有?从 bundle
加载它
如果你有某种类型的数据文件——.plist、csv、json,不管怎样——可能有文件名、歌曲名称、艺术家、日期等。
- 加载包中包含的 PDF 文件的数据
- 在下载文件夹中附加 PDF 文件的数据
- 按字母顺序对完整列表进行排序
- 用户选择了一首歌曲
- 文件
downloadsPath/filename.pdf
是否存在?
- 是吗?加载它
- 没有?从 bundle
加载它
无需跟踪数据中的文件位置 - 只需在您想要加载它时找到它。
在我现有的应用程序中,我有大约 450 个非常小的 PDF 文件,它们是歌曲的歌词。它们都存储在一个名为(适当地)“ThePDFs”的目录中。这样做的缺点是每次我想添加一组新歌词时,我都必须发布应用程序更新。我想做的是使用 Parse 服务器之类的东西指向在线存储的 PDF,并允许用户 select 这些并将它们添加到他们现有的列表中。
但是,我认为我不可能或不允许我使用外部 PDF 并将它们写入名为“ThePDFs”的目录中?如果不允许,以所有歌曲都在一个列表中的方式实现此目的的好方法是什么?我知道我可以将它们下载到应用程序的文档文件夹中,但是我在多个位置都有歌曲,并且在一个 tableview 中访问它们可能会更加困难。我想在第一次启动该应用程序时,我可以将所有 PDF 从捆绑部分复制到文档目录中,然后从中搜索它?
我知道我有很多选择,我只是想知道我是否遗漏了什么。 更新 所以,我正在尝试第一个选项,将 PDF 保留在原处,并制作一个 PLIST,其中包含每首歌曲的名称以及它在文件系统中的位置。然后,当添加新歌曲时,它会做同样的事情,我可以从 PLIST 文件中读取以获取所有歌曲并能够打开它们,无论它们在哪里。我现在的问题是设置初始 PLIST,以及我为每个后续添加所做的操作背后的逻辑。我得到的问题是
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];
}
首先,您是对的,您不能将文件添加到位于 run-time 的应用程序包中。
因此,有多种方法可以解决此问题,具体取决于您要为用户提供的功能。
首先,您可以:
- 在您的应用程序包中包含现有的 PDF
- 在启动时检查远程服务器是否有新的 PDF
- 将新的 PDF 下载到本地应用程序文件夹中
从两个位置生成数据列表以在单个 table 中显示确实是一项相当 straight-forward 和 not-at-all 的复杂任务。
其次,您可以:
- 在您的应用程序包中包含 NO 个 PDF
- 在启动时检查远程服务器是否有新的 PDF(首次启动时它们都是新的)
- 将 PDF 下载(当然是在后台线程上)到本地应用文件夹
现在您只需要在一个位置管理文件。
第三,你可以:
- 在您的应用程序包中包含 NO 个 PDF
- 在启动时检查远程服务器的可用 PDF 列表
- 在用户选择时检索 PDF on-demand
- 可选择在本地“缓存”它们 - 因此仅在尚未选择/下载 PDF 时才检索
编辑
您真的不需要知道文件位置...
我不知道您有哪些与每个 PDF 文件关联的信息,因此,为简化起见,我们假设您正在显示 PDF 文件名列表(没有其他数据)。
大体思路可以是:
- 获取捆绑包中的 PDF 文件列表
- 在下载文件夹中附加 PDF 文件列表
- 按字母顺序对完整列表进行排序
- 用户选择了一个 PDF
- 文件
downloadsPath/filename.pdf
是否存在?- 是吗?加载它
- 没有?从 bundle 加载它
- 文件
如果你有某种类型的数据文件——.plist、csv、json,不管怎样——可能有文件名、歌曲名称、艺术家、日期等。
- 加载包中包含的 PDF 文件的数据
- 在下载文件夹中附加 PDF 文件的数据
- 按字母顺序对完整列表进行排序
- 用户选择了一首歌曲
- 文件
downloadsPath/filename.pdf
是否存在?- 是吗?加载它
- 没有?从 bundle 加载它
- 文件
无需跟踪数据中的文件位置 - 只需在您想要加载它时找到它。