将文件写入 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
      • 加载它

无需跟踪数据中的文件位置 - 只需在您想要加载它时找到它。