原文:http://www.raywenderlich.com/17811/how-to-make-a-simple-mac-app-on-os-x-10-7-tutorial-part-13

     原创译文,转载注明出处:http://blog.csdn.net/mamong/article/details/8458224

本教程由iOS Tutorial Team成员Ernesto García发布,他是一位Mac和iOS开发者,CocoaWithChurros.的创始人。

现在是iOS开发者的好时候,你不仅可以在iPhone和iPad应用商店里发布你的应用,而且你还可以使用这些基本技能成为一个Mac开发者,因为它们两者的开发是相当接近的。

假若你是一个iOS开发者,对学习成为一个Mac开发者的基础充满好奇,想了解如何从iOS应用迁移到桌面上来,那么这个教程适合你。

在本教程里,你将建立你的第一个Mac应用,也就是先前我们在教程《How To Create A Simple iPhone App 》中建立的iOS应用的Mac版本。

如果你已经跟着那个教程做过一遍,那么你将对这个里许多步骤相当熟悉,同时,你也会看到iOS和Mac编程之间的差异。

假如你没有看过那个教程,不要着急,这对于阅读和理解本教程不是必要的,我们会指导你一步步走下去。

创建这个应用时,你将会学到如下内容:

  • 如何在Xcode里创建一个Mac应用
  • 学习Mac应用的基本结构
  • 学习OSX和iOS之间的差异
  • 如何使用Table Views,包括增删行
  • 如何使用text field,button和image view
  • 如何从你的硬盘里选择一张图片,或者用你的电脑摄像头拍摄一张照片
  • 如何处理window resizing 
      

本教程适合Mac初级开发者,假定你熟悉objective-c编程和Xcode。为了跟随本教程,建议有iOS编程的知识,但这不是硬性要求。

在本系列分为三部分。在第一部分,我们将涉及到如何下载一张昆虫名录model,并且将它们显示在Table view里。(跳到第二部分或者第三部分)

开始

创建一个Mac项目和创建一个iOS项目是非常相似的,仍然使用Xcode,但是使用不同的模版。前往Xcode菜单“File->New Project",在跳出的窗口里选择“Mac OS X”区域里的“Application”,然后点击“Next”。

在下一页,你将输入这个应用的信息。在“Product Name”里输入“ScaryBugsMac”,选择一个独一无二的“Company Identifier”,苹果建议使用域名的倒序形式。将剩余的文本框留空。

最后,确保只有“Use Automatic Reference Counting”被选中,而其他的选择框没有被选中。当你完成这一切之后,选择“Next”。

现在Xcode会询问你保存项目的路径。选择你电脑里的一个文件夹,然后点击“Create”.

项目已经建立,现在有了一个单个窗口的简单Mac应用。我们来看看它是啥样子的。找到“Run”按钮,它应该在Xcode顶部工具栏中的左边。点击它,xcode就会编译这个应用。当Xcode编译完后,你将会看到应用的主窗口。

这表明了三点:首先,说明你选择了正确的模版,它工作了!其次,说明这是一个不错的起点。第三,说明这和iOS编程有些非常大,而且显而易见的差别:

  • 窗口不必像iPhone或者iOS那样拥有一个铺满屏幕的固定尺寸,它是完全可以改变尺寸的
  • Mac应用可以拥有不止一个窗口,而且你还可以最小化他们等等

现在我们来对这个窗口进行点改变,让它显示一些虫子的信息。正如在iOS里一样,第一件要做的事情就是建一个View Controller。在这个view里,你将定义主程序的用户界面。

建立一个View Controller,前往菜单栏“File\New\File…”,在弹出的窗口里,选择“OS X\Cocoa\Objective-C class”,点击“Next”。

将这个类命名为“MasterViewController”,在“Subclass of”中输入“NSViewController”。确保“With XIB for user Interface”被选中,点击“Next”.

在弹出的最后一个窗口再次里选择“Create”。现在一个新的view Controller已经建立。在你的项目导航器应该显示类似如下:

建好view controller后,该是放些UI控件在view上面。在项目导航器里点击“MasterViewController.xib”,它会将你刚才建立的View controller的可视化表现形式呈现给你。

Interface Builder让你以可视化的方式去创建用户界面。你仅仅需要拖曳一个组建到你的View,根据应用的需要,将其放在合适的位置,调整它的大小。

第一个想法,你的应用需要做的事情是显示一个虫子的列表。为此,你需要一个Table View。在OSX里,这个控件叫NSTableView(和iOS里的UITableView类似)。

如果你熟悉iOS编程,你也许能够发现这里的一个模式。许多在UIKit中的用户界面相关的类都是从OSX AppKit中迁移过去的。因此,它们中的一些仅仅是从Mac中的前缀NS变成了iOS中的UI。

因此,根据经验,如果你好奇Mac中是否存在一些你知道的,喜欢的iOS控件,你可以试着找找这些以NS为前缀的类。你会惊讶你找到了这么多---NSScrollView, NSLabel, NSButton,还有更多。注意在某些情况下,这些控件也许和iOS里的变体有些不同。

用户界面控件位于屏幕右边的底部,确保选中第三个标签(UI控件的标签),找到NSTableView(你可以拖动控件列表里的滚动条来找到它,也可以在控件盘的搜索栏里输入NSTableView)。

从控件盘里拖曳一个table view到view上,将它放在左上角附近。不要担心table的尺寸,等下处理这个问题。

你现在有了一个table在上面的view,但是你还没将这个view的控制器添加到主窗口,因此它不会显示出来。你需要在Application Delegate完成这个。在项目导航器里选择“AppDelegate.m”。

为了使用一个新的view controller,必须告诉Application Delegate它的存在,因此你需要做的第一件事情是导入view controller的头文件。添加如下内容到“AppDelegate.m”:在“#import “AppDelegate.h””下一行,”@implementation AppDelegate”之前,添加

[cpp] view plaincopy
  1. #include "MasterViewController.h"

现在你要为这个view controller创建一个property/instance。

添加如下代码到刚才那行代码的下面,“@implementation AppDelegate”之前。注意根据新的auto-synthesize特性,properties不再需要被synthesize,所以你就这样设置:

[cpp] view plaincopy
  1. @interface  AppDelegate()
  2. @property (nonatomic,strong) IBOutlet MasterViewController *masterViewController;
  3. @end

现在Application Delegate有了一个MasterViewController property,但是view仍然不会被显示在应用的屏幕上。为了创建一个新的view,你需要实例化这个变量。然后,你需要将这个新创建的view添加到应用程序的主窗口。

这些要在应用程序启动的时候完成。Application delegate有一个applicationDidFinishLaunching方法,在应用程序启动的时候会被操作系统调用。那就是你添加所有初始化代码的地方,这也意味着这只是在程序启动的时候被执行一次。

假如你熟悉iOS编程,这个方法和iOS里的方法– (BOOL)application:didFinishLaunchingWithOptions:launchOptions是等效的。

让我们来创建view controller,并且将它添加到主窗口。在applicationDidFinishLaunching:中插入如下代码:

[cpp] view plaincopy
  1. // 1. Create the master View Controller
  2. self.masterViewController = [[MasterViewController alloc] initWithNibName:@"MasterViewController" bundle:nil];
  3. // 2. Add the view controller to the Window's content view
  4. [self.window.contentView addSubview:self.masterViewController.view];
  5. self.masterViewController.view.frame = ((NSView*)self.window.contentView).bounds;

以上代码有两个作用。首先,使initWithNibName:方法从nib文件里创建一个新MasterViewController。一旦它建立了,就被添加到主窗口。OSX中的窗口(NSWindow类)被创建的时候总是包含一个默认的view,叫做contentView,它自动根据窗口的尺寸调整自身大小。假如你要将自己的view添加到窗口上,你总是需要使用sddSubview方法将它添加到contentView上面。

最后一行设置你的view的大小以匹配窗口的初始尺寸。再次对比iOS编程,这有些不同。在iOS里,你会设置窗口的根视图控制器(rootViewController),但是根视图控制器在OSX里不存在,因此你需要将你的view添加到窗口的内容视图(content View)里。

假如现在你点击“Run”,你将看到主窗口显示了你那个带有table view的视图。非常好---我们来干点别的。

发怵小虫数据模型:组织

到目前为止,你已经有了一个包含一个漂亮的table view的窗口。但是事实上它也没做什么。你想让它显示些令人惊慌的虫子的信息----但是等一下,你还没有任何要展示的数据!

没有数据,这真的让我很难过。因此,在接下来的步骤中,你将为应用建立一个数据模型,但是在这之前,教你一个组织项目导航器里文件的方法。

注意:这是一个可选的部分,展示如何组织文件到组里。假如你看过《How To Create A Simple iPhone App on iOS 5 Tutorial》或者已经知道怎么做了,可以跳过这部分。

这是你当前在Xcode项目导航器里文件结构:

默认模板以应用的名字创建了一个组,还有一个存放支持文件(plist, resources等)。当你的项目变得越来越大,你将和很多文件打交道,查找你要的文件变得越来越困难。

在这部分,我们将教你一个组织你的文件的方法。这个组织方式因人而异,因此你可以根据自己的喜好来改变它。

首先,你需要创建一个组来存放用户界面文件,我们将命名它为“GUI”。创建这样一个组,你可以Ctrl+Click或者右键“ScaryBugsMac”组。在弹出的菜单中选择“New Group”。这个被创建的组自动被选中,你可以输入一个新的名字“GUI”。

现在,拖曳用户界面文件到那个组(AppDelegate.h/.m MasterViewController.h/.m/.xib andMainMenu.xib)。在拖曳后,你的项目导航器看起来应该类似这样:

现在创建“Scary”的第二个组,命名为“Model”。在接下去里,我们将为你的应用创建一些数据模型文件,你需要将这些文件添加到这个组。到此,你的导航器应该类似这样:

在我们开始之前,让我们谈论下如何组织这些东西:

  • ScaryBugData:包含虫子的名字和排名
  • ScaryBugDoc:包含原尺寸的图片,缩略图,ScaryBugData

我们这样设置的理由是为了这个教程的接下去部分更容易些,在那儿我们将开始保存我们的数据到硬盘。

发怵小虫数据模型:实现

Note: If you’ve followed the How To Create A Simple iPhone App on iOS 5 Tutorial, you will find that this section is (almost) identical to that. One of the good things about Mac/iOS programming is that they share most of the SDK, obviously, except the UI classes and some OS specific parts.

So, when you’re creating the model and classes that don’t need user interface, you will find that most of your code will likely just work on Mac, or it will work with some minor changes.

For instance, in this case, changing the ScaryBug model classes from iOS to Mac only required one change. UIImage does not exist in OSX, so you just needed to change it to OSX’s image class, NSImage. And that was it!

让我们来创建这个模型。我们开始创建这个ScaryBugData文件。

在项目导航器里,Control-Click你刚才创建的模型组,在菜单里点击“New File...”,选择“OS X\Cocoa\Objective-C class”模版,然后点击“Next”。

命名这个类为“ScaryBugData”,将它的父类设置为“NSObject”,点击“Next”。

在最后弹出来的窗口里再次点击“Create”。假如一切顺利的话,你的项目导航器应该类似这样子:

接下去我们为“ScaryBugData”添加些源代码。

首先,选中“ScaryBugData.h”文件,用下面的代码替换它里面所有的内容:

[cpp] view plaincopy
  1. #import <Foundation/Foundation.h>
  2. @interface ScaryBugData : NSObject
  3. @property (strong) NSString *title;
  4. @property (assign) float rating;
  5. - (id)initWithTitle:(NSString*)title rating:(float)rating;
  6. @end

这是非常简单的东西----我们仅仅声明了一个拥有两个property的对象,两个property分别是:一个表示虫子名字的字符串,一个表示你对它令人发怵程度评价的浮点数。这时你要用到下面两个property属性:

  • strong:表示指定运行时应该自动保持对一个对象的强引用。这只是一个花哨的说法,大意就是只要存在一个指向对象的引用,ARC运行时会将这个对象驻留在内存里,当没有引用剩下的时候,就销毁它。更多内容见教程《Beginning ARC in iOS 5》
  • assign:表示直接设置property,没有涉及内存管理。你经常用它来设置float之类的基本类型(非对象)。

你还为这个类定义了一个初始化方法,因此你可以在创建一个虫子的时候设置它的名字和发怵等级。转到“ScaryBugData.m”,用下面的代码替换:

[cpp] view plaincopy
  1. #import "ScaryBugData.h"
  2. @implementation ScaryBugData
  3. - (id)initWithTitle:(NSString*)title rating:(float)rating {
  4. if ((self = [super init])) {
  5. self.title = title;
  6. self.rating = rating;
  7. }
  8. return self;
  9. }
  10. @end

这也相当简单。你创建了一个初始化方法,使用传入的参数给你的实例变量赋值。注意到这里没必要使用dealloc,因为你用了ARC;也没必要synthesize你的property,因为auto-synthesize特性。

好了,“ScaryBugData”就那么多。现在根据前面的步骤创建另外一个NSObject的子类,这次命名为“ScaryBugDoc”。使用下面的代码替换”ScaryBugDoc.h”的内容:

[cpp] view plaincopy
  1. #import <Foundation/Foundation.h>
  2. @class ScaryBugData;
  3. @interface ScaryBugDoc : NSObject
  4. @property (strong) ScaryBugData *data;
  5. @property (strong) NSImage *thumbImage;
  6. @property (strong) NSImage *fullImage;
  7. - (id)initWithTitle:(NSString*)title rating:(float)rating thumbImage:(NSImage *)thumbImage fullImage:(NSImage *)fullImage;
  8. @end

这里没有什么需要特别注意到地方------仅仅创建了一些实例变量/property和一个初始化方法。用下面的代码替换“ ScaryBugDoc.m ”:

[cpp] view plaincopy
  1. #import "ScaryBugDoc.h"
  2. #import "ScaryBugData.h"
  3. @implementation ScaryBugDoc
  4. - (id)initWithTitle:(NSString*)title rating:(float)rating thumbImage:(NSImage *)thumbImage fullImage:(NSImage *)fullImage {
  5. if ((self = [super init])) {
  6. self.data = [[ScaryBugData alloc] initWithTitle:title rating:rating];
  7. self.thumbImage = thumbImage;
  8. self.fullImage = fullImage;
  9. }
  10. return self;
  11. }
  12. @end

就这样,你的数据模型就完成了!

现在你编译并且运行你的应用来检查是否一切运行正常。按照预期你应当看到一个空的列表,因为你还没有将数据模型和UI相链接。

现在你有了数据模型,但是你还没有任何数据。你需要创建一个“ ScaryBugDocs”列表,并且你将它存在一个NSMutableArray里。我们将在MasterViewController里添加一个property来跟踪你的虫子列表。

选择“MasterViewController.h”,将下面这行代码放在@interface和 @end lines之间:

[cpp] view plaincopy
  1. @property (strong) NSMutableArray *bugs;

这将是我们用来跟踪虫子列表的实例变量/property。接下去让我们来将它勾起来。

发怵小虫图片和样品数据

现在,MasterViewController类已经做好准备来接受一个虫子列表。但是话说回来,你还是没有任何数据。

在添加数据之前,我们需要一些令人发怵的从子的图片!你可以从教程《How To Create A Simple iPhone App on iOS 5 Tutorial》中下载这些图片或者去网上找些你喜欢的令人发怵的虫子的图片:]。

下载好这些文件或者得到了你自己喜欢的文件,将它们拖到你的项目导航器的文件结构树的根位置。当弹窗出现时,确保选中了“Copy items into destination group’s folder (if needed)”,然后点击“Add”。

假如你想把这些东西保存得更加合理,你可以为这些虫子图片创建一个子组,然后拖曳这些文件到里面。

现在,让我们来创建样品数据。选中“AppDelegate.m”,将下面一行添加到文件顶部,#include “MasterViewController.h”的下面:

[cpp] view plaincopy
  1. #import "ScaryBugDoc.h"

为了创建传给MainViewController的样本数据,在applicationDidFinishLaunching方法里做些变动,修改在“[self.window.contentView addSubview:self.masterViewController.view];”这一行上面进行:

[cpp] view plaincopy
  1. // Setup sample data
  2. ScaryBugDoc *bug1 = [[ScaryBugDoc alloc] initWithTitle:@"Potato Bug" rating:4 thumbImage:[NSImage imageNamed:@"potatoBugThumb.jpg"] fullImage:[NSImage imageNamed:@"potatoBug.jpg"]];
  3. ScaryBugDoc *bug2 = [[ScaryBugDoc alloc] initWithTitle:@"House Centipede" rating:3 thumbImage:[NSImage imageNamed:@"centipedeThumb.jpg"] fullImage:[NSImage imageNamed:@"centipede.jpg"]];
  4. ScaryBugDoc *bug3 = [[ScaryBugDoc alloc] initWithTitle:@"Wolf Spider" rating:5 thumbImage:[NSImage imageNamed:@"wolfSpiderThumb.jpg"] fullImage:[NSImage imageNamed:@"wolfSpider.jpg"]];
  5. ScaryBugDoc *bug4 = [[ScaryBugDoc alloc] initWithTitle:@"Lady Bug" rating:1 thumbImage:[NSImage imageNamed:@"ladybugThumb.jpg"] fullImage:[NSImage imageNamed:@"ladybug.jpg"]];
  6. NSMutableArray *bugs = [NSMutableArray arrayWithObjects:bug1, bug2, bug3, bug4, nil];
  7. self.masterViewController.bugs = bugs;

这里你使用了the ScaryBugDoc的初始化方法来创建四个虫子样本,给每一个传入名字,评级和图片信息。将这四个样本放入NSMutableArray,然后通过bugs property传给masterViewController。

你终于有了些数据!编译运行你的程序,确保所有都正常工作,没有发生任何错误。但是我们仍然在用户界面看不到任何东西,但是这次view controller已经有它需要的数据了,我们可以着手用户界面上的工作,最终显示出你的发怵小虫子列表。

一个不同的虫子列表

为了显示虫子列表,你需要设置table view从你的模型中得到虫子列表。

在OSX中,table view控件叫做NSTableView,它和UITableView类似之处是它也能显示成列的数据,但是不同之处是NSTableView每一行可以显示多列。

和UITableView一样,NSTableView每一行都有些cell。然而它们的功能最近有了些改变:

  • OSX10.7Lion之前:table view的cells是一个继承自NSCell类的特别的类。它们不是基于view的,处理draw和鼠标事件是程序员的职责。
  • OSX10.7以后:有了一类新的table view---基于view的table view。这个table view工作的方式非常类似UITableView。它的cells是一类特别的view(NSTableViewCell),使用这样的view就非常类似在iOS的用法,这样就简单多了。

在本教程里,你将使用这样新的基于view的Table view。我们将涉及到基础部分,但是假如你想学习更多关于NSTableView的,你可以阅读《Table View Programming Guide》,在这里面非常好的解释了table view如何工作的。

在设置用户界面之前,你需要在nib文件里做一个小小的改变,关闭“Auto Layout”。Auto Layout是OSX10.7中新介绍的特性,意在根据程序员订下的一些规则,自动处理用户界面上的控件尺寸改变。Auto Layout超出了本教程的范围,使解释一些东西变得比较困难,因此你要先关掉它。在Auto Layout关掉之后,autoresizing就可以配置,并且和在iOS 5项目里具有相同的运行结果。

选择MasterViewController.xib。Interface Builder界面打开,在窗口右侧的实用工具盘(Utilities panel)里,确保选中“File Inspector”(它位于左侧标签栏第一个)。在“File Inspector”标签中取消选中“Use Auto Layout”。

做完这些,你需要对main window做同样的操作。选中“MainMenu.xib”里的window,同样取消auto layout。

现在我们已经准备好了。让我们开始设置你的table view,这样它就可以显示一个ScaryBugDocs列表了。在项目导航器里选择“MasterViewController.xib”,在Interface Builder的view里选中你的table view。注意table view是内嵌在一个scroll view里的。因此你第一次点击它,你会选中scroll view。

为了选中table view,再次点击它(不是双击,第二次点击在前一次后面一小会儿)。另外一个选中它的办法是直接点击右侧对象盘(objects panel)里的table view。

选中之后紧接着要做的事情是改变table view为“view based”,因为Interface builder默认创建的是“cells based”。

为了改变它,确保你选中了屏幕右侧的特性盘(properties panel)的“Attributes Inspector Tab”。然后在“Content Mode” 中选择 “View Based”。你的列表不需要很多列,因此改变“Columns property”为1。

为了定制这个列表,选中特性“Alternating Rows”,这样就会以蓝白交替的方式绘制行。不要选中“Headers”特性,这样就移除了表头,因为在本教程里我们不需要。

在移除多余的列之后,剩下的列比table view窄,为了调整它的大小,点击“table column”(点击三次table view或者使用右侧的对象盘),调整这一列的大小以铺满整个table的宽度。

接下来的步骤是配置table view使用的cell view。你的列表需要显示虫子的图片和名字。你需要包含一个image和一个text  field的cell来显示信息。Interface Builder有一个预配置的包含一个image和text field的NSTablecellView,因此你要用那个。在窗口底部左侧的“Object library panel”里有一个“Image & Text Table Cell View”,将它拖到你的table view里。

做完这些之后,你的table里现在有两种不同的cell。选中原来的cell(没有齿轮图标的cell),按下delete键来删除。

最后一步是改变cell的高度,因为它对于显示虫子的图片来说是在太小了。你应当将其的高度设置为32.选中cell,然后在Xcode窗口的右侧特性盘(Utilities panel)里打开大小检查器“Size Inspector”标签。你可以在高度配置盘(Height panel)里设置cell的高度为32.

另外一种办法是拖动cell底部的边框直到你得到了想要的高度。这之后,image和text field有了些偏移,为了修复这个,选中它们,然后拖到cell的中间。你可以改变image view的大小,改变text field的字体来满足你的需要。现在设计的table view应该像这样:

现在你要设置列标识(column identifier),这是一个你给table view的每一列取的名字,因此当你想要执行一些操作或者你收到了一些来自某列的通知,你就可以识别出是哪一列。

这并非本教程严格需要的,因为你只有一列,但是这样做是一个不错的练习,当在其他项目里需要建立一个多列的table view的时候,你就不会有什么问题了。选中table column(记住你要在table view中点击三次或者使用左边的Objects panel)。在这之后,打开Utilities panel里的“Identity Inspector”标签。在那里Identifier由“Automatic”变为 “BugColumn”。

这就是table UI的配置。现在你需要连接table view和MasterViewController,这样它们就能知道彼此的存在了。

和iOS一样,table view使用两个property来让table和它的controller来通信:数据源(datasource)和委托(delegate)。

基本上,数据源是一种告诉table view它要显示什么数据的类。委托也是一个类,它控制数据如何显示,并且从table view接收通知,例如当一个cell被选中。

委托和数据源通常是(但是现在是总是)同一个controller。这本例子中,数据源和委托都是你的MasterViewController类。这可以通过编程来实现,但是在本教程中,你将要在Interface Builder来实现这种关联。

选中你的table view,在“Utilities Panel”里选择连接检查器(Connections Inspector,有个指向右侧箭头图标的那个)。在Outlets区域,你会看到delegate和datasource。(原文此处有错误“you will see the delegate in the datasource”,翻译版本已修复)先来连接delegate。点击delegate右侧的小圆圈,然后拖到左侧PlaceHolders panel的File’s Owner上(也就是MasterViewController)。

正如你被告知的那样,table view的delegate是MasterViewController。当你实例化你应用里的视图控制器,将为我们自动创建这种连接。现在对datasource outlet重复这个过程。做完这些后,你一定可以看到两条指向File’s Owner的连接,像这样:

就这样,现在我们要往你的view controller里添些必要的代码来显示你的虫子列表。选择MasterViewController.m,将下面的添加到文件的顶部,#import “MasterViewController.h”这一行下边:

[cpp] view plaincopy
  1. #import "ScaryBugDoc.h"
  2. #import "ScaryBugData.h"

然后复制下面的代码到文件的底部,@end之前:

[cpp] view plaincopy
  1. - (NSView *)tableView:(NSTableView *)tableView viewForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row {
  2. // Get a new ViewCell
  3. NSTableCellView *cellView = [tableView makeViewWithIdentifier:tableColumn.identifier owner:self];
  4. // Since this is a single-column table view, this would not be necessary.
  5. // But it's a good practice to do it in order by remember it when a table is multicolumn.
  6. if( [tableColumn.identifier isEqualToString:@"BugColumn"] )
  7. {
  8. ScaryBugDoc *bugDoc = [self.bugs objectAtIndex:row];
  9. cellView.imageView.image = bugDoc.thumbImage;
  10. cellView.textField.stringValue = bugDoc.data.title;
  11. return cellView;
  12. }
  13. return cellView;
  14. }
  15. - (NSInteger)numberOfRowsInTableView:(NSTableView *)tableView {
  16. return [self.bugs count];
  17. }

好了,来看看我们在这儿做了些什么。为了在table view里显示数据,你需要实现至少两个方法。一个是数据源的numberOfRowsInTableView:方法,这个方法由操作系统调用来询问数据源(在本例中是MasterViewController)“我该要显示多少行?”你只需要用数组里的虫子列表回应。

使用这个方法,table view就知道了要显示多少行,但是仍然不知道显示在每列里的哪个cell,也不知道那些cell应该有什么信息。

这些由tableView:viewForTableColumn:row方法来完成。这个方法由操作系统为table view里的每行和每列调用。在方法里,你需要创建合适的cell,并且用你需要的信息填充它。假如你有iOS编程经验,你会发现这和UITableView的工作方式非常类似。numberOfRowsInTableView:非常类似iOS中的numberOfRowsInSection:,同样地,viewForTableColumn:row也和iOS中的cellForRowAtIndexPath:类似。不同之处在于在iOS里你需要根据它的section 和row来设置cell,而在OSX里,你根据row和column来设置cell。cellForRowAtIndexPath:是一个非常重要的方法,因此让我们来仔细地看一下这个方法:

[cpp] view plaincopy
  1. - (NSView *)tableView:(NSTableView *)tableView viewForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row {
  2. // Get a new ViewCell
  3. NSTableCellView *cellView = [tableView makeViewWithIdentifier:tableColumn.identifier owner:self];
  4. // Since this is a single-column table view, this would not be necessary.
  5. // But it's a good practice to do it in order by remember it when a table is multicolumn.
  6. if( [tableColumn.identifier isEqualToString:@"BugColumn"] )
  7. {
  8. ScaryBugDoc *bugDoc = [self.bugs objectAtIndex:row];
  9. cellView.imageView.image = bugDoc.thumbImage;
  10. cellView.textField.stringValue = bugDoc.data.title;
  11. return cellView;
  12. }
  13. return cellView;
  14. }

首先你通过调用makeViewWithIdentifier:来得到一个cellView。这个方法将会创建(或者再利用)一个合适的基于identifier的单列的cell(就是你在Interface Builder里设置的)。当你拥有这样一个cell之后,就该用信息来填充它。我们依靠列来差异地进行这一步。这就是为什么我们要检查identifier是否为“BugColumn”。假如列的identifier是“BugColumn”,就根据ScaryBugDoc里的信息设置image和text field。在本例子里只有一种列,因此这个检查不是必须的。然而知道如何处理多列的情况将对你非常有帮助,因为在你自己的应用里,你可能需要那些。

这就是所有你需要显示在table view里的信息。这仅仅是一个在Interface Builder中定义properties和connections,在你的view controller里实现两个方法的问题。

是时候编译运行这个程序了。假如一切正常的话,你应该可以看到一个显示Scary Bugs列表的table view!

Where to go from here?

Here is a sample project with all of the code we’ve developed so far in this tutorial series.

Next in the Series, you will learn how to add a detail view, and how to add/edit/delete bugs from your list. you will also cover how to polish the User Interface and handle the window resizing to make your app look great at any size!


This is a post by iOS Tutorial Team Member Ernesto García, a Mac and iOS developer founder of CocoaWithChurros.

开发一个简单的Mac应用相关推荐

  1. java计算机毕业设计vue开发一个简单音乐播放器(附源码、数据库)

    java计算机毕业设计vue开发一个简单音乐播放器(附源码.数据库) 项目运行 环境配置: Jdk1.8 + Tomcat8.5 + Mysql + HBuilderX(Webstorm也行)+ Ec ...

  2. 一个html写的app首页,如何快速开发一个简单好看的APP控制页面

    原标题:如何快速开发一个简单好看的APP控制页面 导读 机智云开源框架为了让开发者快速开发APP,已将用户登录,设备发现,设备配网等功能做成了各个标准模块,仅保留控制页面让开发者自行开发设计,节省了开 ...

  3. 利用WCF的callback机制开发一个简单的多人游戏模型

    本文介绍了如何利用WCF和callback机制开发一个简单的多人在线游戏模型. 运行过程如下: 当game service 启动之后,若干个客户端便会自动连接到服务器.当某个客户端点击join gam ...

  4. [译]使用 Rust 开发一个简单的 Web 应用,第 4 部分 —— CLI 选项解析

    原文地址:A Simple Web App in Rust, Part 4 -- CLI Option Parsing 原文作者:Joel's Journal 译文出自:掘金翻译计划 本文永久链接:g ...

  5. php开发mvc教程,php开发一个简单的MVC

    本文通过实例为大家介绍用php开发一个简单mvc的方法,起到势砖引玉的作用,本文比较适合刚接触mvc的朋友. MVC其实就是三个Model,Contraller,View单词的简称. Model,主要 ...

  6. Nginx开发一个简单的HTTP过滤模块

    本文将学些开发一个简单的HTTP过滤模块,它能够对Content-Type为text/plain的包体前加上前缀字符串prefix. <一> 过滤模块的调用顺序 过滤模块可以叠加,也就是说 ...

  7. python可视化界面编程 pycharm_pycharm开发一个简单界面和通用mvc模板(操作方法图解)...

    文章首先使用pycharm的 PyQt5 Designer 做一个简单的界面,然后引入所谓的"mvc框架". 一.设计登录界面 下面开始第一个话题,使用pycharm的 PyQt5 ...

  8. 开发一个简单的WebPart

    开发一个简单的WebPart,首先我们需要对Visual Studio .NET 2003进行相应功能的扩展,我们可以在微软的网站下载到一个扩展功能包,名字叫:WebPartTemplatesforV ...

  9. java开发一个简单的通讯录

    java开发一个简单的通讯录 ArrayList的综合应用 import java.util.*; public class ContactNote{static Scanner sc=new Sca ...

  10. 开发一个简单易用的SDK的详细步骤(超详细,超适用)

    文章目录 开发一个简单易用的SDK的详细步骤 创建starter步骤 关键点 总结 开发一个简单易用的SDK的详细步骤 创建starter步骤 1.新建一个 spring boot 初始化项目 2.添 ...

最新文章

  1. typora背景变黑
  2. Linux环境下安装Python第三方库
  3. 如何使用可外部化的接口在Java中自定义序列化
  4. 运算放大器基本公式_还在被三阶/四阶/运算放大器滤波器PLL这些概念困扰?这篇文章帮你搞懂它...
  5. 大芒果 mysql 断开_大芒果3.3.5进入显示 与服务器断开连接
  6. 医院计算机房相关制度,医院信息科机房管理制度.doc
  7. Java程序员笔试面试之String5
  8. c语言中order函数,C语言order的用法
  9. 电离层对高分辨率星载SAR成像的影响1——电离层的相关定义
  10. SEO利器 - 网页内容监控之百度自动推送
  11. Spring框架的七大模块
  12. Congestion问题怎么解决?
  13. eggs和egg是什么意思_eggs是什么意思_eggs的翻译_音标_读音_用法_例句_爱词霸在线词典...
  14. 智能扫地机器人陀螺仪导航
  15. cfadisk,让电脑把sd卡识别成硬盘
  16. MTCNN人脸及特征点检测--基于树莓派3B+及ncnn架构
  17. 惠普电脑打开BIOS的方法
  18. windows访问控制列表ACL
  19. 设计模式之禅学习总结
  20. 到底谁适合学Python呢?

热门文章

  1. Wing Loss 论文阅读笔记
  2. JAVAOooooo。。。。。ooo0000OOOOO
  3. poi4.0升级踩坑合集(更新中)
  4. 【Camera基础(二)】摄像头驱动原理和开发V4L2子系统驱动架构
  5. 两行代码让人戒掉游戏
  6. android手机管理器在哪里打开,小米手机任务管理器在哪?怎么打开?
  7. 盘点7款常用的数据分析工具
  8. stm32 定时器_基于STM32定时器ETR信号的应用示例
  9. 使用enum代替Constants
  10. winrar.msi_如何使WinRAR自动化以从setup.exe和MSI文件制作单个文件安装程序