如何在OS X 10.7上开发一个简单的应用教程(一)

2023-11-05

     原文: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”之前,添加

#include "MasterViewController.h"

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

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

@interface  AppDelegate()
@property (nonatomic,strong) IBOutlet MasterViewController *masterViewController;
@end

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

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

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

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

// 1. Create the master View Controller
self.masterViewController = [[MasterViewController alloc] initWithNibName:@"MasterViewController" bundle:nil];
 
// 2. Add the view controller to the Window's content view
[self.window.contentView addSubview:self.masterViewController.view];
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”文件,用下面的代码替换它里面所有的内容:

#import <Foundation/Foundation.h>
 
@interface ScaryBugData : NSObject
 
@property (strong) NSString *title;
@property (assign) float rating;
 
- (id)initWithTitle:(NSString*)title rating:(float)rating;
 
@end

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

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

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

#import "ScaryBugData.h"
 
@implementation ScaryBugData
 
- (id)initWithTitle:(NSString*)title rating:(float)rating {
    if ((self = [super init])) {
        self.title = title;
        self.rating = rating;
    }
    return self;
}
 
@end

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

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

#import <Foundation/Foundation.h>
 
@class ScaryBugData;
 
@interface ScaryBugDoc : NSObject
 
@property (strong) ScaryBugData *data;
@property (strong) NSImage *thumbImage;
@property (strong) NSImage *fullImage;
 
- (id)initWithTitle:(NSString*)title rating:(float)rating thumbImage:(NSImage *)thumbImage fullImage:(NSImage *)fullImage;
 
@end

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

#import "ScaryBugDoc.h"
#import "ScaryBugData.h"
 
@implementation ScaryBugDoc
 
- (id)initWithTitle:(NSString*)title rating:(float)rating thumbImage:(NSImage *)thumbImage fullImage:(NSImage *)fullImage {
    if ((self = [super init])) {
        self.data = [[ScaryBugData alloc] initWithTitle:title rating:rating];
        self.thumbImage = thumbImage;
        self.fullImage = fullImage;
    }
    return self;
}
 
@end

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

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

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

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

@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”的下面:

#import "ScaryBugDoc.h"

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

// Setup sample data
ScaryBugDoc *bug1 = [[ScaryBugDoc alloc] initWithTitle:@"Potato Bug" rating:4 thumbImage:[NSImage imageNamed:@"potatoBugThumb.jpg"] fullImage:[NSImage imageNamed:@"potatoBug.jpg"]];
ScaryBugDoc *bug2 = [[ScaryBugDoc alloc] initWithTitle:@"House Centipede" rating:3 thumbImage:[NSImage imageNamed:@"centipedeThumb.jpg"] fullImage:[NSImage imageNamed:@"centipede.jpg"]];
ScaryBugDoc *bug3 = [[ScaryBugDoc alloc] initWithTitle:@"Wolf Spider" rating:5 thumbImage:[NSImage imageNamed:@"wolfSpiderThumb.jpg"] fullImage:[NSImage imageNamed:@"wolfSpider.jpg"]];
ScaryBugDoc *bug4 = [[ScaryBugDoc alloc] initWithTitle:@"Lady Bug" rating:1 thumbImage:[NSImage imageNamed:@"ladybugThumb.jpg"] fullImage:[NSImage imageNamed:@"ladybug.jpg"]];
NSMutableArray *bugs = [NSMutableArray arrayWithObjects:bug1, bug2, bug3, bug4, nil];
 
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”这一行下边:

#import "ScaryBugDoc.h"
#import "ScaryBugData.h"

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

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

         好了,来看看我们在这儿做了些什么。为了在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:是一个非常重要的方法,因此让我们来仔细地看一下这个方法:

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

        首先你通过调用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.




本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何在OS X 10.7上开发一个简单的应用教程(一) 的相关文章

  • python 自定义类支持缓冲协议_Python编程技巧整理

    过滤列表中的数据 实际案例 过滤掉列表里面的负数 案例分析 filter function or None iterable py2返回一个列表 py3返回一个迭代器 列表解析 使用timeit来测试函数的运行时间 案例代码 python3
  • threw exception [Request processing failed; nested exception is java.lang.NullPointerException] with

    异常描述 空值异常 java lang NullPointerException 这是因为我自己在拦截器拦截的时候进行的登录判断时通过session获取到一个空的user并使用这个实体类的getUserName方法获取用户名出现了错误 这是
  • C++ 作业 day1 7/14

    脑图
  • 性能监控-grafana+prometheus+node_exporter

    Prometheus是一个开源的系统监控和报警工具 它由SoundCloud开发并于2012年发布 后来成为了一个独立的开源项目 并得到了广泛的应用和支持 Prometheus的主要功能包括采集和存储各种系统和应用程序的监控数据 并提供强大
  • 基础算法题——学长的白日梦(快速幂、快速逐步求积)

    学长的白日梦 题目简单明了 只要将计算出 xi 即可 两个卡点 快速幂 快速逐步求积 由于这道题 mod 999999997 mod mod gt 10 19 不能直接用快速幂解决 中间求积会爆 于是我卡在逐步求余上动弹不得 唉 看了题解后
  • selenium找不到chrome浏览器的解决办法

    传入chrome exe的绝对路径 例如 options webdriver ChromeOptions options binary location C Program Files x86 Google Chrome Applicati
  • 关于RC电路特点以及几种常见的典型应用

    RC电路是由电阻R以及电容C组成的电路 只需要一个电阻R以及一个电容C 通过这两个器件的不同串并联 并选取不同的参数 可以实现几种不同的功能 RC电路在模拟电路 数字电路中得到了广泛的应用 R 的连接方式 RC 串联电路 电路的特点 由于有
  • mybatisplus group by 归组

    QueryWrapper
  • web前端文件上传可选择的4种方式

    在web前端开发中 文件上传属于很常见的功能 不论是图片 还是文档等等资源 或多或少会有上传的需求 一般都是从添加文件开始 然后读取文件信息 再通过一定的方式将文件上传到服务器上 以供后续展示或下载使用 本文将讲述文件上传中所能用到的4种添
  • 【AtCoder Beginner Contest 252】部分题解

    D Distinct Trio 题意 给定一个长度为 n n n的序列 a a a 求使得 1
  • Python编程:从入门到实践 项目《外星人入侵》完整代码

    blog github hexo的blog链接 github 我的github传送 学习 Python编程 从入门到实践 有段时间了 跟着书本把所有代码都敲了一遍 感悟很深 现在完成了 外星人入侵 项目 对于库 类 函数 方法都有一定的理解
  • Android 多行RadioGroup 实现

    需求如下 思路有多种 可以用自定义布局 RecycleView 代码动态控制布局 RadioGroup 等方式实现 今天我用的RadioGroup 实现思路如下 布局文件如下
  • DLNA第一步UPnP协议栈

    前面公司有DLNA项目 研究了一下 在网上关于DLNA的资源很少 就将自己的心得写出来 以供参考 其它的关于DLNA的介绍就不多说 要了解DLNA需要了解upnp 因为DLNA在upnp之上 初学者可以从http www upnp org下
  • std::sort 升序 ? 降序

    Std sort 这个函数 大家知道用 而且入可以 使用一个自定义的元素对比函数 比较郁闷的是 老是忘了 这个函数返回TRUE 对排序结果的影响 升序还是降序 于是用GTEST写了一段代码 测试代码 将就些看吧 class HandHogR
  • 自底向上和自顶向下的架构设计区别

    某日小明上数学课 他的老师给了很多个不同的直角三角板让小明用尺子去量三角板的三个边 并将长度记录下来 两个小时过去 小明完成任务 把数据拿给老师 老师给他说 还有一个任务就是观察三条边之间的数量关系 又是两个小时 聪明的小明连蹦带跳走进了办

随机推荐

  • vue父组件向子组件传值

    非常简单 相信大家一看就懂 复制到浏览器即可使用 注意别忘了引入vue哦 div div pmsg div div
  • 一台计算机如何安装2个版本的python,互不影响呢

    python学习过程中 很多教程都是python2 版本的 但是python2 到2020年就不在维护了 所以 现在教大家如何在一台计算机上安装python2 和python3 互不影响 可以自如的切换 不用任何第三方软件 简单省力 一次配
  • 熊啸锋:掌握这4个步骤,你的销售额至少增加3倍,风险降低10倍

    你好 我是熊啸锋老师 认识我的人都知道 我有一套快速成交陌生客户的秘诀 让你在零粉丝的情况下 快速的冷启动 用好这个秘诀之后 在不增加成本的情况下 你的利润至少增加3倍 风险降低10倍 具体怎么做呢 在分享这个秘诀之前 我们先来看看大部分人
  • latex中长公式换行,很好的办法

    今天在编辑公式时 有一个公式很长 写到一行就出去了 当时之前换行都是方程组或者在括号完之后换 都没有问题 但是今天我也换行的是在括号中间断开 这样出现问题 编辑的时候会出错误提醒 上网查了一些论坛 也有人和我一样的问题 但是都没有解决方案
  • 操作系统存储器管理之连续、页式、段式、段页式存储器管理方式

    基本内存分配方案 4 3 连续分配存储管理方式 连续分配方式 是指为一个用户程序分配一个连续的内存空间 4 3 1单一连续分配 内存分为两个区域 系统区 用户区 应用程序装入到用户区 可使用用户区全部空间 最简单 适用于单用户 单任务的OS
  • 抖音帐号注册需要注意什么

    虽然短视频是大势所趋 但是我们在抖音上也不能瞎玩 注册时需要避开哪些坑 怎样才能更快的吸引到第一批粉丝 新手一定不要错过今天的课程干货 首先 你要记住账号注册一卡一号一手机新手在抖音账号注册 其次 简介中需要用简练的语言体现出账号的内容及特
  • 基于VirtualBox虚拟机安装Ubuntu图文教程

    一 下载安装VirtualBox 官网下载VirtualBox 目前版本 VirtualBox 5 1 8 for Windows hosts x86 amd64 下载好了安装VirtualBox 一路Next就可以了 这个比较简单 运行V
  • 创意特效分享:用代码绘制网页上的爱心

    在网页设计中 为了增加用户体验和吸引用户的注意力 常常需要添加一些特效来增添页面的互动性和趣味性 其中 爱心特效是一种常见且受欢迎的效果 能够在用户与网页进行交互时展现出迷人的动态效果 通过使用HTML CSS和JavaScript 我们可
  • MySQL - 表字段的唯一键约束

    设置表字段唯一约束 UNIQUE UK 当数据库表中某个字段上的内容不允许重复时 可以使用UK约束进行设置 UK约束在创建数据库时为某些字段加上 UNIQUE 约束条件 保证所有记录中该字段上的值不重复 如果在用户插入的记录中该字段上的值与
  • switch 语句,while 循环,for 循环和do while循环

    switch 语句 switch 语句是 种特殊形式的 if else 结构 于判断条件有多个结果的情况 它把多重的 else if 改成更易 可读性更好的形式 例如 include
  • Linux多线程:条件变量

    条件变量的类型 pthread cond t 作用 满足某个条件阻塞或者解除阻塞某个线程 int pthread cond init pthread cond t restrict cond const pthread condattr t
  • CTFweb篇——html源代码签到题

    0x00 前言 做CTF的web中Html查看源代码的题还是比较简单 对我而言 就是在源代码中找寻相关的关键字或者线索 0x01 签到题 进入靶场发现当前页面 最开始怀疑是靶场原因没进去 仔细研究后发现自己被障眼法了 初次做题的时候 在懵逼
  • java.lang.ArithmeticException: Division undefined 或者 java.lang.ArithmeticException: / by zero

    今天线上报了一个这样的错误 经过排查发现是因为对Bigdecimal类型做除法divide 运算时 除数为0导致的 加了一个非0的判断就好了 当我们的被除数为整型 short int long 时 除数不能为0 除数如果为double 即
  • npm install报错

    1 在安装sass时报错 C Users dong Downloads CapecAnalyzer master CapecAnalyzer master WebAppCapec node modules node sass src lib
  • IDEA2022性能优化的一些设置

    因为本人电脑配置比较低 导致IDEA用起来卡卡的 经过设置之后有所缓解 可以参考 我这里IDEA版本为 2022 1 2 注意区分版本 1 关掉没用的插件 IDEA预装的插件是很多的 有很多都用不上 比如说新版本会有 code with m
  • tcp port numbers reused出现原因_图文并茂详解TCP的3次握手+4次挥手+11种状态集

    2TCP的介绍 TCP也叫传输控制协议 Transmission Control Protocol 是一种面向连接的 可靠的 基于字节流的传输层通信协议 由IETF的RFC 793定义 3TCP的特点1 面向连接 TCP通信需要经过创建连接
  • 接口测试详细步骤(入门+实用)

    1 拿到接口文档的时候先分析文档 分析的内容有 请求类型 必填项 选填项 入参 出参及描述 2 编写测试用例 测试用例的编写参考下图 3 利用postman jmeter或者其它接口测试工具执行测试用例 4 把测试后的的响应数据与数据库中自
  • 【StyleGAN2论文精读CVPR_2020】Analyzing and Improving the Image Quality of StyleGAN

    StyleGAN2论文精读CVPR 2020 Analyzing and Improving the Image Quality of StyleGAN 一 前言 Abstract 1 Introduction 2 Removing nor
  • linux下的守护进程(daemon)和系统日志(syslog)

    目录 守护进程daemon 参数 编程示例 日志系统syslog 函数原型 openlog函数及其参数说明 打开系统日志 参数说明 参数说明 编程示例 守护进程daemon Unix Linux中的守护进程 Daemon 类似于Window
  • 如何在OS X 10.7上开发一个简单的应用教程(一)

    原文 http www raywenderlich com 17811 how to make a simple mac app on os x 10 7 tutorial part 13 原创译文 转载注明出处 http blog csd