Storyboards 使用指南 iOS 9: 第一部分

这是一篇翻译作品,水平有限,希望各位指正。各位同学最好去看原文:
Storyboards Tutorial in iOS 9: Part 1

注意:在04-01-2016更新了Xcode 7.3,iOS 9.3和Swift 2.2
教程团队成员Matthijs Hollemans原始贴子

故事板是一个令人兴奋的功能,在iOS 5首次引入,为你构建用户界面节省大量的时间。
让我用一张图片向你展示storyboard是什么,这就是你在指南中你在教程中将要构建的故事板:



你可能不知道这个应用程序的功能,但你可以清楚地看到它有哪些场景,以及它们是如何关联的。
故事板有许多优点:

  • 您可以在“场景”中直观地布置所有视图控制器,并说明它们之间的关联关系。使用故事板可以更好的概述您的应用程序的所有场景。
  • 故事板可以描述各种场景的转场。这些转场被称为"segues",您可以通过在故事板中连接视图控制器来创建它们。感谢"segues"让你需要更少的代码来照顾你的UI。
  • 故事板通过原型单元格和静态单元格功能,可以更轻松地处理表格视图。您几乎可以完全在故事板编辑器中完成您的表格视图设计,从而减少您必须编写的代码量。
  • 故事板使您更容易使用自动布局,该功能允许您定义定义其位置和大小的元素之间的数学关系。这个强大的功能使得更容易处理不同屏幕尺寸和尺寸的设备。在本教程中,您将使用“自动布局”,但不在本教程的范围之内。您可以在自动布局教程 或者 观看视频系列获取更多信息。

在这个故事板的教程中,你创建一个简单的应用程序,可以让你创建一个游戏和玩家列表,并评估他们的技能水平。在这个过程中,你将学会用故事版完成最常见的任务。

入门

启动Xcode并创建一个新项目。使用单视图应用程序模板作为起点。


填写模板选项如下:

  • Product Name: Ratings
  • Organization Name: fill this in however you like
  • Organization Identifier: the identifier that you use for your apps
  • Language: Swift
  • Devices: iPhone
  • Use Core Data: not checked
  • Include Unit Tests and UI Tests: not checked

Xcode创建项目后,Xcode主窗口看起来这样:



新项目包含两个类,AppDelegate 和 ViewController,本教程的主角:Main.storyboard文件。
这是一个只有肖像的应用程序,继续之前,找到 Deployment Info > Device Orientation取消屏幕左右旋转选项。
让我们看一看这个storyboard文件。在项目导航栏中点击storyboard文件打开它,在界面生成器编辑器:



一个视图控制器的官方故事板术语是“场景”,但你可以互换使用这些术语。在故事板中一个场景代表一个视图控制器。

这里您可以看到一个包含空视图的单视图控制器。在视图控制器的左侧有箭头指向表明,它是故事板的最开始显示的视图控制器。

在故事板编辑器中构建布局是从对象库通过拖动控件到你的视图控制器完成(见右下角)的。

注意:你会注意到默认场景大小是一个正方形。Xcode 7在故事板中使用Auto Layout and Size Classes. Auto Layout and Size Classes允许您制作灵活的用户界面,可以方便地调整大小,这对于支持各种大小的iPhone和iPad都很有用。去更多的学习Size Classes,看看我们的Adaptive Layout video tutorial series.
在这个教程中,你可以选择故事板的大小,这样可以更容易地了解最终屏幕上的布局。

在你开始之前,调整模拟器场景大小为iPhone 6 /6。
在视图列表中选择View Controller。如果你没有看到“视图列表”,单击故事板画布左下角的这个按钮:


选择Attributes Inspector下的Simulated Metrics,改变SizeiPhone 4.7 inch.

在storyboard的场景将显示尺寸为iPhone 6/6S,大小为4.7英寸的iPhone模拟器。
“推断”是在故事板的模拟器指标的默认设置。模拟器的指标是storyboard的视觉设计助手,展示最终设计界面。记住,他们不是在运行时使用的。

去感受storyboard的编辑过程。从右下角的对象库拖动一些控件到空白视图控制器。



当拖动控件时,它们将显示在左边的视图列表内:



故事板显示所有你的视图控制器的内容。当前在你的故事板只有一个视图控制器(或场景),但在本教程的过程中,您将添加几个其他视图。

有一个视图列表上面的场景称为Dock:



码头显示场景中的层级最高的对象。 每个场景至少有一个视图控制器对象,第一响应对象,和一个返回的item,但它也可能有其他顶级对象。码头便于连接到接口和方法。如果您需要将某物连接到视图控制器,您可以简单地拖动到它的图标到Dock。

注意:你可能不会经常使用第一响应对象。这是一个代理对象,指的是任何对象在任何给定的时间具有第一响应状态。例如,你可以通过按钮的触摸事件成为第一响应者:选择器。如果通过按压某一文本框获得输入焦点,也就是现在的第一响应者,将文本粘贴进去。

运行这个应用程序,它应该与编辑器中设计完全相同(可能看起来不同于下面的截图-这只是为了演示,并不会在以后的教程中使用):



您定义的单视图控制器被设置为初始视图控制器 – 但是应用程序怎么加载它? 查看应用程序代理方法找到答案。打开AppDelegate.swift文件,你可以看到下面的源代码:

import UIKit

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {

var window: UIWindow?

func application(application: UIApplication, >didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
// Override point for customization after application launch.
return true
}

@UIApplicationMain属性在AppDelegate类文件的顶部指定为模块的入口。
使用应用程序委托继承的故事板UIResponder,并具有UIWindow属性是一项要求。所有的方法实际上都是空的。即使application(_:didFinishLaunchingWithOptions:)简单地返回true。
秘密在Info.plist文件中。在项目导航器栏中,点击Info.plist文件你会看到:



应用程序的故事板用"UIMainStoryboardFile"作为关键字,亦称为"Main storyboard file base name",以指定应用程序启动时必须加载的故事板的名称。当此设置存在时,UIApplication将加载命名的故事板文件,自动从该故事板实例化“初始视图控制器”,然后将该控制器的视图放入一个新UIWindow对象。

您还可以在“常规选项卡”和“部署信息”部分的“项目设置”中看到这一点:



现在正式创建评级程序的几个视图控制器。

只需要将其添加到我的选项卡

你要建立的评级应用程序有一个带两个屏幕的选项卡界面。使用故事板创建选项卡很容易。

你将从一个新的故事板开始,所以切换到Main.storyboard文件,删除之前的视图控制器。这可以通过单击视图列表中的视图控制器并按“ Delete”键来完成。

将Tab Bar Controller从对象库拖到画布中。你可能首先想最大化你的Xcode窗口,因为Tab Bar控制器附带两个视图控制器,你需要一些操作的空间。 你可以通过双击画布放大和缩小,也可以通过按住Ctrl键单击画布并选择缩放级别来设置缩放比例。
为了方便起见,请再次更改模拟器以将场景显示为iPhone。如前所述,,在视图列表中选择Tab Bar Controller,在属性检查器,改成4.7英寸的尺寸。这也将改变在故事板中的两个嵌入视图控制器来模拟iPhone 6或6。


新的Tab Bar Controller预先配置两个附加的视图控制器,分别作为标签。UITabBarController是所谓的容器视图控制器因为它包含一个或者多个其他视图控制器。其他两个容器控制器是Navigation Controller和 Split View Controller (稍后您将使用Navigation Controller)。

容器关系由Tab Bar Controller和它包含的视图控制器之间的箭头来表示。嵌入关系,特别是指图标所看到的箭头中间的箭头结构。


注意:如果要将Tab Bar Controller及其附属视图控制器移动为一组,双击缩小,然后你可以按着⌘键并点击选中拖动多个场景。可以一起移动他们。(选定的场景有一个淡蓝色轮廓。)

将label拖到第一个视图控制器(当前标题为“ Item 1”)中,双击,设置文字“First Tab”.也将label拖到第二视图控制器(“Item2”)中,并设置文字“Second Tab”.你可以在标签之间切换时看到实际发生的情况。

注意:编辑器缩放时,不能将控件拖到场景中。您将需要通过双击画布返回到正常的缩放级别。

构建并运行,你会在控制台看到类似的内容:

Ratings[18955:1293100] Failed to instantiate the default view controller for UIMainStoryboardFile 'Main' - perhaps the designated entry point is not set?

幸运的,这里的错误很清楚 - 您从未设置程序入口,这意味着你在删除了前面使用的场景后,没有设置初始视图控制器。要解决这个问题,选择Tab Bar Controller找到属性检查器。选中Is Initial View Controller单选框。



在画布中,指向已删除视图控制器的箭头现在指向 Tab Bar Controller:



这意味着,当你运行应用程序,程序会把Tab Bar Controller当做主屏幕。
运行程序试试看。该应用程序现在有一个tab bar,您可以在两个视图控制器之间切换选项卡:

提示:要更改初始视图控制器,还可以在视图控制器之间拖动箭头。

Xcode实际上是建立一个tabbed应用程序模板(难怪叫标签应用模板),你可以使用,为了知道他如何很好的工作,你也可以手动创建一个Tab Bar Controller.

注意:如果连接超过五个场景的Tab Bar Controller,当你运行应用程序时会自动获取更多…选项卡”。相当灵巧!

添加一个Table View Controller

当前连接到Tab Bar Controller的两个场景都是常规UIViewController实例。你可以用一个UITableViewController替换第一个场景。
单击选中视图列表中的第一个视图控制器,之后删除。从对象库拖动一个新的Table View Controller 到画布中以前的场景的位置:



现在,您希望将Table View Controller放置在导航控制器中。选择Table View Controller,选择Xcode菜单栏Editor\Embed In\Navigation Controller.这将另一个控制器添加到画布中:



您还可以从对象库中拖放导航控制器并嵌入表视图,但嵌入命令可以比普通拖拽方法节省时间。
因为导航控制器也是一个容器视图控制器(和Tab Bar Controller类似),它有一个关系箭头指向表视图控制器。您也可以在视图列表中看到这些关系:

请注意,嵌入Table View Controller 的控制器给它一个导航栏。界面生成器自动将其放在那里,因为这个场景现在将显示在导航控制器的框架内。那不是一个真实的UINavigationBar 对象,是一个模拟的对象。模拟指标将推断出场景周围的环境,当它位于导航控制器内部时,当它位于Tab Bar控制器内时的选项卡栏等上显示导航栏。
新的控制器是方形的。当你嵌入他们的Tab Bar Controller,会在一瞬间,他们将改变他们的模拟大小,以配合父场景。
要将这两个新场景连接到Tab Bar Controller,从Tab Bar Controller拖拽到导航控制器。放开时,出现一个小的弹出菜单。选择Relationship Segue – view controllers 选项:



这将在两个场景之间创建新的关系箭头。这也是一种嵌入关系,您可以看到与Tab Bar Controller所包含的其他控制器。
标签栏控制器有两个嵌入关系,各自是一个标签。导航控制器本身与Table View Controller有嵌入关系。
创建此新连接时,将在选项卡栏控制器中添加新选项卡,简单的命名"item".对于这个应用程序,你希望这个新的场景成为第一个标签,可以拖动选项卡改变他们的位置顺序。

运行应用程序试一下。第一个选项卡现在包含导航控制器内的表视图。

在添加应用程序的一些实际功能之前,您需要理清故事板。您将命名第一个“ Players”标签和第二个“ Gestures”。您不要在Tab Bar控制器本身上更改此选项,应该在连接这些选项卡的视图控制器中进行更改。
一旦将视图控制器连接到Tab Bar控制器,就会获得一个Tab Bar Item对象,您可以在视图列表或场景底部看到它。您可以使用此标签栏来配置标签栏控制器上显示的标题和图像。
选择导航控制器中的标签栏项目,并在属性检查器中将其标题设置为"Players":

将视图控制器的标签栏项目从第二个选项卡重命名为"Gestures",方式相同。

精心设计的应用程序也应该在这些选项卡上放置一些照片。在本教程资源包含子文件夹命名的图像。将该文件夹拖到项目中的Assets.xcassets子文件夹中。

返回Main.storyboard文件,在“ 玩家选项卡栏项目的属性 ”检查器中,选择添加Players.png图片。



注意视图列表中的场景标题现在更改为"Players"。

或者,您可以双击导航栏并在其中更改标题。请注意,您应该双击Table View Controller中的模拟导航栏,而不是导航控制器中实际的导航栏对象。

运行应用程序,惊叹标签栏的神奇,创建不需要编写一行代码!


原型Cells

原型单元格允许您直接从故事板编辑器中轻松地为表格视图单元格设计自定义布局。
Table View Controller附带一个空白的原型单元格。单击该单元格以选择它,在“ 属性检查器”中将“ Style”选项设置为“ Subtitle”。这会立即改变单元格的外观,以包含两个标签。

在故事板上拥有如此多的可堆叠内容,有时可能难以点击您想要的内容。如果感觉麻烦,有几个选择。一个是您可以通过项目中画布左侧的“视图列表”选择。第二个是一个方便的快捷键:按住Ctrl + Shift并点击你感兴趣的区域。会弹出窗口,允许您直接通过光标下选择任何元素。

如果您之前已经使用过table views,并且手动创建了自己的单元格,则可以将其视为UITableViewCellStyle.Subtitle样式。使用原型单元格,您可以像您刚才那样选择一种内置单元格样式,也可以创建自己的定制设计(快速编程)。
将属性Accessory设置为Disclosure Indicator,并设置Identifierw为PlayerCell。所有原型单元都应具有重用标识符,以便您可以在代码中引用它们。



运行应用程序,没有任何改变。这不奇怪:您仍然必须为表添加数据源,以便知道要显示哪些行。这正是你接下来要做的事情。
向项目添加新文件。在iOS / Source下选择Cocoa Touch Class模板。将类命名为PlayersViewController并将其设为UITableViewController的子类。取消选中创建XIB文件。选择Swift语言,然后点击Next,然后点击Create。



回到故事板文件并选择表视图控制器(确保您选择实际的视图控制器,而不是其中的一个视图)。在身份检查器中,将其类设置为PlayersViewController。这是通过您的自定义视图控制器子类和故事板场景关联的基本步骤。不要忘记这个否则你的类不会被使用!

从现在开始,当您运行应用程序时,桌面视图控制器就是该类的一个实例PlayersViewController。

表视图应显示players列表,因此现在您将为应用程序创建主数据模型 - 包含Player对象的数组。使用iOS / Source下的Swift File模板将命名为Player的新文件添加到项目中。

将Player.swift中的代码替换为:

import UIKit

struct Player {
var name: String?
var game: String?
var rating: Int

init(name: String?, game: String?, rating: Int) {
self.name = name
self.game = game
self.rating = rating
}
}
这里没什么特别的。Player只是这三个属性的容器对象:玩家的名字,他们正在玩的游戏,以及1到5颗星的等级。
接下来,您将创建一个测试Player对象数组,然后将其赋值给PlayersViewController的一个数组。首先使用名为SampleData的Swift File模板创建一个新文件。将其添加到SampleData.swift的结尾:
//Set up sample data

let playersData = [
Player(name:"Bill Evans", game:"Tic-Tac-Toe", rating: 4),
Player(name: "Oscar Peterson", game: "Spin the Bottle", rating: 5),
Player(name: "Dave Brubeck", game: "Texas Hold 'em Poker", rating: 2) ]

在这里,您定义了一个名为playersData的常量,并向其分配了一个硬编码的Player对象数组。
现在类 PlayersTableViewController: UITableViewController在PlayersViewController.swift中添加一个Player数组属性,以保存玩家列表:

var players:[Player] = playersData

您可以在定义Player变量时简单地在PlayersViewController中设置示例数据。但是由于以后可能会从plist或SQL文件提供此数据,因此处理视图控制器外部的数据加载是明智之举。
现在你有一个充满Player对象的数组,可以继续把数据源和PlayersViewController关联起来。仍然在PlayersViewController.swift中,将表视图数据源方法替换为以下内容:

override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}

override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return players.count
}

真正的工作发生在cellForRowAtIndexPath。将此方法替换为当前注释掉的方法:

override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath)
-> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("PlayerCell", forIndexPath: indexPath)

let player = players[indexPath.row] as Player
cell.textLabel?.text = player.name
cell.detailTextLabel?.text = player.game
return cell
}

该方法dequeueReusableCellWithIdentifier(_:forIndexPath:)将检查是否存在可再重用的单元格。如果没有,它将自动分配一个原型单元格并将其返回给您。所有您需要做的是在故事板编辑器中提供您在原型单元格上设置的重用标识符 - 在本例中为PlayerCell。不要忘记设置该标识符,否则这个小方案将无法正常工作!
运行应用程序,可以看到,桌面视图中有玩家!



使用这些原型单元只需要几行代码。我觉得那真是太棒了。

注意:在这个应用程序中,您只使用一个原型单元格,但如果您的表需要显示不同类型的单元格,那么您可以简单地向故事板添加其他原型单元格。您可以复制现有的单元格以创建一个新单元格,也可以增加Table View的Prototype Cells属性的值。确保给每个单元格一个重用标识符。

设计您自己的原型单元格

使用标准单元格样式对于许多应用程序来说都可以,但是对于这个应用程序,您需要在单元格的右侧添加一个显示Player评级(一到五颗星)的图像。标准单元格样式不支持该位置中的图像视图,因此您必须进行自定义设计。

切换回Main.storyboard,在表视图中选择原型单元格,并在属性检查器上将其Style属性设置为Custom。默认标签现在消失。

首先使cell高一点。更改“ Size inspector”检查器中的“ Row Height”值(选择“ Custom”后)或拖动单元格底部的句柄。使cell高60点。

将两个Label对象从对象库拖动到单元格中,并将它们大致放在标准标签之上。只需使用属性检查器中的字体和颜色,然后选择您喜欢的内容。将顶部标签的文本设置为“ Name”,将底部标签设置为“ Game”。

使用Command +单击选择视图列表中的Name和Game标签,然后选择Editor\Embed In\Stack View.

注意:堆叠视图在iOS 9中是新的,并且很好地轻松地布局视图集合。您可以在我们的新书“iOS 9”中了解有关堆栈视图的更多信息。

将图像视图拖动到单元格中,并将其放置在公开指示符旁边的右侧。在尺寸检查器中,使其宽81点,高35点。将其模式设置为中心(在“属性”检查器中的“查看”下),以便放入此视图的任何图像都不会拉伸。

Command +单击视图列表中的堆叠视图和图像视图以选择它们。选择Editor\Embed in\Stack View. Xcode将创建一个包含这两个控件的新的水平堆栈视图。
选择此新的水平堆栈视图,并在属性检查器中将对齐方式更改为中心,将分布更改为等间距。
现在设置这个控件的一些简单的自动布局。在故事板的右下角,点击图标:



将顶部约束更改为Top:0,Right:20,Bottom:0和Left:20。确保在值中高亮显示四个红色指针,如图所示。点击弹出窗口底部的Add 4 Constraints。



如果您的堆栈视图有橙色约束,表明位置约束警告。要解决这个问题,请选择水平堆栈视图,然后选择 Editor\Resolve Auto Layout Issues\Update Frames(在菜单的所选视图部分)。堆叠视图定位正确,橙色约束错误消失。
要将图像视图放置在堆叠视图中,请选择视图列表中的图像视图,然后选择Editor\Resolve Auto Layout Issues\Add Missing Constraints(在菜单的“所选视图”部分)。
原型单元的最终设计看起来像这样:

因为这是一个专门设计的cell,你不能再使用UITableViewCell的textLabel和detailTextLabel属性来放置文本标签。此单元格不再包含这些属性标签; 它们仅适用于标准cell类型。相反,您将使用tag值来查找标签。

为了简单起见,这里使用了tag。在本教程的后面,您将创建一个继承自UITableViewCell的自定义类,并包含与单元格视图上的标签相对应的属性。

在“属性”检查器中,将“ Name”标签的tag值设置为100,将“ Game”标签的tag设置为101,将“ Image View”标签的tag值设置为102。
然后打开PlayersViewController.swift在类的末尾新添加方法imageForRating,如下所示:

func imageForRating(rating:Int) -> UIImage? {
let imageName = "(rating)Stars"
return UIImage(named: imageName)
}

很简单 - 根据评分返回不同的星形图像。仍然在PlayersViewController中,更改tableView(_:cellForRowAtIndexPath:)方法为以下内容:

override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("PlayerCell", forIndexPath: indexPath) //1

let player = players[indexPath.row] as Player //2

if let nameLabel = cell.viewWithTag(100) as? UILabel { //3
nameLabel.text = player.name
}
if let gameLabel = cell.viewWithTag(101) as? UILabel {
gameLabel.text = player.game
}
if let ratingImageView = cell.viewWithTag(102) as? UIImageView {
ratingImageView.image = self.imageForRating(player.rating)
}
return cell
}

以下是您代码的含义:
1.dequeueReusableCellWithIdentifier将使用重用标识符(PlayerCell如果可用)将现有单元格出队,如果不可用则创建一个新的标识符。
2.您查找与Player正在填充的行对应的对象并将其分配player。
3.标签和图像由单元格上的标签查找,并填充player对象中的数据。

应该这样做 现在再次运行应用程序,可能看起来像这样:


嗯,看起来不是很正确 - cell似乎被挤压了。你确实改变了原型单元格的高度,但是表格视图并没有考虑到这一点。有两种方法来解决它:您可以更改表视图的行高属性,或实现该tableView(tableView:heightForRowAtIndexPath:)方法。前者在这种情况下很好,因为我们只有一种类型的单元格,我们提前知道高度。

注意:tableView(tableView:heightForRowAtIndexPath:)如果您提前不知道单元格的高度,或者不同的行可能具有不同的高度,才可以使用。
返回Main.storyboard,在“ 表视图” 的“ Size inspector”检查器中,将行高设置为60:



再次运行应用程序,看起来好多了!



顺便说一下,如果您通过拖动其句柄而不是键入值来更改单元格的高度,则表视图的Row Height属性也会自动更改。所以这可能是你第一次正常工作。

使用Cell的子类

table view已经很好用,但是我不是使用tag值访问原型cell的标签和其他子视图的大粉丝。如果您可以将这些标签连接到接口,然后使用相应的属性,那将会更加整洁。事实证明,你可以。
使用Cocoa Touch Class模板向项目添加新文件。将它命名为PlayerCell并使它继承自UITableViewCell。不要选择创建XIB的选项,因为您的故事板中已有单元格。
在PlayerCell类中添加这些属性,就在类定义的下面:

@IBOutlet weak var gameLabel: UILabel!
@IBOutlet weak var nameLabel: UILabel!
@IBOutlet weak var ratingImageView: UIImageView!

所有这些变量都是IBOutlets,可以连接到故事板中的场景。
将此属性添加到IBOutlets下方:

var player: Player! {
didSet {
gameLabel.text = player.game
nameLabel.text = player.name
ratingImageView.image = imageForRating(player.rating)
}
}
无论何时设置player属性,它将使用正确的信息更新IBOutlets。
将方法imageForRating(:)从PlayersViewController 移动到PlayerCell类,以将单元格细节保留在同一个类中。
返回Main.storyboard文件,选择原型单元格PlayerCell,并将其类更改为Identity inspector上的“PlayerCell”。现在,当您向表单查看数据源时dequeueReusableCellWithIdentifier(
:forIndexPath:),将返回一个PlayerCell实例,而不是常规的UITableViewCell。
请注意,您给这个类与重用标识符相同的名称 - 它们都称为PlayerCell - 但这只是因为我喜欢保持一致。类名称和重用标识符无关,因此您可以按照不同的名称命名。
现在将标签和图像视图连接到这些接口。导航到故事板中的“ Connections Inspector”,然后从画布或“视图列表”中选择“ Player Cell ”。从“ 连接”检查器中的nameLabel Outlet拖动到“视图列表”或“画布” 中的“ Name”标签对象。为了复用gameLabel和ratingImageView。

重要:您应该将控件连接到table view cell,而不是view controller!您可以看到,无论何时数据源通过dequeueReusableCellWithIdentifier方法向表单视图提供新的单元格,table view 不会提供实际的原型单元格,但是可以复用(或者如果可能的话,可以回收之前的单元格之一)。
这意味着PlayerCell在任何给定的时间将有不止一个实例。如果要将label从cell连接到视图控制器上的接口,则标签的几个副本将尝试使用相同的接口。这是自找麻烦。(另一方面,将原型单元格连接到视图控制器上的动作完全正常,如果您UIControls的单元格上有自定义按钮或其他按钮,则可以这样做)。

现在你已经连接了这些属性,你可以简化数据源代码。在PlayersViewController中,更改tableView(_:cellForRowAtIndexPath:)为:

override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath)
-> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("PlayerCell", forIndexPath: indexPath)
as! PlayerCell

let player = players[indexPath.row] as Player
cell.player = player
return cell
}

大概是这个样子。你现在将通过dequeueReusableCellWithIdentifier方法获取一个PlayerCell,然后你可以简单地将正确的player传递给cell。在PlayerCell中设置player变量将自动将传值到标签和图像视图中,单元格将使用您在故事板中连接的IBOutlet。使用原型单元格如何使表格视图不那么麻烦呢?
运行应用程序并尝试。它应该仍然像以前一样,但在幕后,它现在使用您自己的表视图单元格子类!

最后说一句.能力一般,水平有限,欢迎指正,有问题可以发邮件到1432103394@qq.com

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,839评论 6 482
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,543评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 153,116评论 0 344
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,371评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,384评论 5 374
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,111评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,416评论 3 400
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,053评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,558评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,007评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,117评论 1 334
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,756评论 4 324
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,324评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,315评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,539评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,578评论 2 355
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,877评论 2 345

推荐阅读更多精彩内容

  • WebSocket-Swift Starscream的使用 WebSocket 是 HTML5 一种新的协议。它实...
    香橙柚子阅读 23,728评论 8 183
  • 发现 关注 消息 iOS 第三方库、插件、知名博客总结 作者大灰狼的小绵羊哥哥关注 2017.06.26 09:4...
    肇东周阅读 12,029评论 4 62
  • 在这个寡淡了感情的城市 钢筋水泥筑起的巨大防护墙隔开了友善和暖阳 当肩膀不能够给人以依靠 当专属的怀抱开始温暖一个...
    意莫安阅读 231评论 2 1
  • 一声叹息吹皱了记忆 泛黄书信旧香四溢 萦绕鼻尖挥之不去的秘密 路灯下的吻礼 辗转千年把爱恨翻洗 从未细细看过你 尤...
    陌诺流年阅读 400评论 15 30
  • 有没有人让你可以无所顾忌的在他/她面前畅所欲言,压根不需要伪装,不怕出笑话,不怕被嘲笑?你在他/她面前永远都是最真...
    冰山圣羽阅读 245评论 0 0