核心数据& TableView& PDFView:这一切是如何结合在一起的?

时间:2015-01-17 13:31:24

标签: objective-c xcode macos cocoa core-data

对于我目前的项目,我想实现一个与Apple Preview应用程序非常相似的用户界面 - 左侧是PDF文件列表,右侧是大型UI部分显示当前选定的文档:

Preview screenshot (理想情况下,左侧的文件列表会显示缩略图而不是文件名,但以后会显示缩略图。)

关于我的背景,我在C ++和Qt方面有丰富的经验,但我是Objective C和XCode的全新手。我在Mac OS X 10.8.5下使用XCode 5.1.1(这是Mountain Lion上的最新版本)。

我已经设置了一个XCode项目,该项目引入了通常的Core Data元素(NSPersistentStoreCoordinatorNSManagedObjectModelNSManagedObjectContext),我添加并连接了文件列表和PDF查看自己:

@interface AppDelegate : NSObject <NSApplicationDelegate>

@property (assign) IBOutlet NSWindow *window;

@property (readonly, strong, nonatomic) NSPersistentStoreCoordinator *persistentStoreCoordinator;
@property (readonly, strong, nonatomic) NSManagedObjectModel         *managedObjectModel;
@property (readonly, strong, nonatomic) NSManagedObjectContext       *managedObjectContext;

@property (weak) IBOutlet NSScrollView *fileList;
@property (weak) IBOutlet PDFView      *pdfView;

(IBAction)saveAction:(id)sender;

@end

覆盖文件列表的UI元素实际上是NSTableView,只有一列且没有标题。 (不确定fileList属性是否真的应该是NSScrollView,但这似乎是添加插座时弹出窗口中唯一的选项。)

到目前为止,我所取得的成就如下:

  1. 在PDF视图中显示PDF文档(带有硬编码路径),代码如下
    NSString    *path   = @"/POSIX/path/to/sample/PDF/document.pdf";
    NSURL       *url    = [NSURL fileURLWithPath: path];
    PDFDocument *pdfDoc = [[PDFDocument alloc] initWithURL: url];
    self.pdfView.document = pdfDoc;
    
  2. 设置核心数据模型:其中最相关的实体是Document,其属性为filename。我想表格视图应该显示一个列表。
  3. 我还为数据模型中的每个实体生成了NSManagedObject个子类,但我还没有使用它们,因为我不知道如何处理它们:o)
  4. 扫描(硬编码)PDF文档的工作文件夹,按谓词过滤并使用文件名填充(或更新)我的Core Data模型 - 即使只有一个获取请求:-)。数据会自动保留在~/Library/Application Support/<organization>.<application>/<application>.storedata
  5. (目前,大多数此功能都捆绑在[AppDelegate applicationDidFinishLaunching]方法中。)

    所以现在,我觉得我已经拥有了大部分所需的功能,我只是没有看到这一切如何在一起发挥作用的大局。

    我的问题:

    1. 如何让表格视图显示我的核心数据模型中存储的文件列表?
      目前,app delegate被设置为表视图数据源和委托,因此根据我的理解,它必须实现一些&#34;数据源协议&#34; (?!?)(和#34; protocol&#34;似乎就像一个界面,只是没有一个类来捆绑它们?!?)
    2. 如何让PDF视图显示在文件列表中选择的文档?
      我有一种感觉需要通知用户选择了一个不同的文件,然后让PDF视图显示该文件...
    3. NSFetchedResultsController如何在这里发挥作用? 我认为它也可以作为表视图数据源,只有在核心数据模型中有任何变化时才会通知它,因此可以自动更新表格视图,例如,列表中的文件消失了?!?
    4. 正如您可能已经说过的那样,我对代表,协议等的理解有限,所以如果有人能够了解主要参与者是谁以及谁与谁联系并得到通知,我会感激不尽。或更新或其他。

      我显然在网上完成了尽职调查,除了正式的Apple文档外,这些页面特别有用:

      但是现在大多数在线资源(包括SO)都集中在iOS或最近的Swift上,虽然我知道有很多相似之处,但我没有任何故事板,主/细节视图控制器或segues等等这些只会增加我的困惑。

      我觉得我非常接近。有人可以帮帮我吗?

1 个答案:

答案 0 :(得分:0)

这是许多可能的方法之一。创建NSViewController的子类以管理主视图的每个部分。例如,我的一个应用程序有一个类来管理类似的列表:

@interface SongsController : NSViewController <NSTableViewDataSource, NSTableViewDelegate, NSDraggingSource>

我在MainMenu.xib中创建了一个实例,并将其作为应用程序委托的强大属性进行连接。它有自己的.xib来设计它的细节。然后在applicationDidFinishLaunching:代码:

[self.mainView addSubview:[self.songsController view]];

mainView是我的主要NSWindow内的拆分视图的占位符子视图。我喜欢NSSplitView因为我通常希望部分可以调整。)这让我可以移动任何内容与应用程序委托之外的列表管理有关。

我倾向于将我的数据处理部分移动到他们自己的类中,一个处理所有CoreData内容的单例,另一个通过应用&#34;业务逻辑&#34;提供数据模型。到CoreData信息。

我的数据模型在这种情况下没有使用NSFetchedResultsController,因为我对列表中显示的内容有很多过滤器,所以自己进行刷新更简单。

这意味着在列表中选择不同的项目归结为:

- (void)tableViewSelectionDidChange:(NSNotification *)aNotification {
    NSTableView *view = [aNotification object];
    NSInteger row = [view selectedRow];
    Song *s = [DATA_MODEL songAtRow:row];
    [[NSNotificationCenter defaultCenter] postNotificationName:mSongChanged object:s];
}

主视图的右侧构造和连接方式略有相同。它会收听mSongChanged通知并更新其到达时显示的内容。

这并没有回答你所有的问题,但也许它会让你的问题变得更加混乱。