在故事板中,如何制作与多个控制器一起使用的自定义单元?

发布于 2025-01-05 10:15:31 字数 946 浏览 2 评论 0原文

我正在尝试在我正在开发的应用程序中使用故事板。在应用程序中,有列表用户,每个列表都包含另一个列表的集合(列表的成员、用户拥有的列表)。因此,相应地,我有 ListCellUserCell 类。目标是让它们在整个应用程序中(即在我的任何表格视图控制器中)可重复使用。

这就是我遇到问题的地方。

如何在情节提要中创建可在任何视图控制器中重复使用的自定义表格视图单元格?

以下是我迄今为止尝试过的具体操作。

  • 在控制器 #1 中,添加一个原型单元,将类设置为我的 UITableViewCell 子类,设置重用 ID,添加标签并将它们连接到类的插座。在控制器 #2 中,添加了一个空原型单元,将其设置为相同的类并像以前一样重用 id。当它运行时,当单元格显示在控制器 #2 中时,标签永远不会出现。在控制器 #1 中工作正常。

  • 在不同的 NIB 中设计每种单元类型,并将其连接到适当的单元类别。在情节提要中,添加一个空原型单元并设置其类并重用 id 以引用我的单元类。在控制器的 viewDidLoad 方法中,为重用 id 注册这些 NIB 文件。如图所示,两个控制器中的单元与原型一样都是空的。

  • 将两个控制器中的原型保留为空,并设置类并重用 id 到我的单元类。完全用代码构建单元格的 UI。单元在所有控制器中都能完美工作。

在第二种情况下,我怀疑原型总是覆盖 NIB,如果我杀死了原型单元,则为重用 id 注册我的 NIB 就可以了。但是这样我就无法设置从单元格到其他框架的segues,这确实是使用故事板的全部意义。

归根结底,我想要两件事:在故事板中连接基于表格视图的流程,并以可视方式而不是在代码中定义单元格布局。到目前为止我不知道如何实现这两个目标。

I'm trying to use storyboards in an app I'm working on. In the app there are Lists and Users and each contains a collection of the other (members of a list, lists owned by a user). So, accordingly, I have ListCell and UserCell classes. The goal is to have those be re-usable throughout the app (ie, in any of my tableview controllers).

That's where I'm running into a problem.

How do I create a custom tableview cell in the storyboard that can be re-used in any view controller?

Here are the specific things I've tried so far.

  • In Controller #1, added a prototype cell, set the class to my UITableViewCell subclass, set the reuse id, added the labels and wired them to the class's outlets. In Controller #2, added an empty prototype cell, set it to the same class and reuse id as before. When it runs, the labels never appear when the cells are shown in Controller #2. Works fine in Controller #1.

  • Designed each cell type in a different NIB and wired up to the appropriate cell class. In storyboard, added an empty prototype cell and set its class and reuse id to refer to my cell class. In controllers' viewDidLoad methods, registered those NIB files for the reuse id. When shown, cells in both controllers were empty like the prototype.

  • Kept prototypes in both controllers empty and set class and reuse id to my cell class. Constructed the cells' UI entirely in code. Cells work perfectly in all controllers.

In the second case I suspect that the prototype is always overriding the NIB and if I killed the prototype cells, registering my NIB for the reuse id would work. But then I wouldn't be able to setup segues from the cells to other frames, which is really the whole point of using storyboards.

At the end of the day, I want two things: wire up tableview based flows in the storyboard and define cell layouts visually rather than in code. I can't see how to get both of those so far.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

哆兒滾 2025-01-12 10:15:31

据我了解,您想要:

  1. 在 IB 中设计一个可在多个故事板场景中使用的单元格。
  2. 根据单元所在的场景,从该单元配置独特的故事板序列。

不幸的是,目前无法做到这一点。要了解为什么您之前的尝试不起作用,您需要更多地了解故事板和原型表视图单元格的工作原理。 (如果您不关心为什么这些其他尝试不起作用,请立即离开。除了建议您提交错误之外,我没有任何神奇的解决方法。)

从本质上讲,故事板只不过是 .xib 文件的集合。当您加载一个具有故事板中的一些原型单元的表视图控制器时,会发生以下情况:

  • 每个原型单元实际上都是其自己的嵌入式迷你笔尖。因此,当表视图控制器加载时,它会遍历原型单元的每个笔尖并调用 -[UITableView registerNib:forCellReuseIdentifier:]
  • 表视图向控制器询问单元格。
  • 您可能会调用 -[UITableView dequeueReusableCellWithIdentifier:]
  • 当您请求具有给定重用标识符的单元格时,它会检查它是否注册了笔尖。如果是,它会实例化该单元的一个实例。这由以下步骤组成:

    1. 查看单元格的类,如单元格笔尖中所定义。调用[[CellClass alloc] initWithCoder:]
    2. -initWithCoder: 方法会遍历并添加子视图并设置在 nib 中定义的属性。 (IBOutlet 也可能在这里连接,尽管我还没有测试过;它可能发生在 -awakeFromNib 中)
  • 您可以根据需要配置单元格.

这里需要注意的重要一点是单元格的和单元格的视觉外观之间是有区别的。您可以创建同一类的两个单独的原型单元,但它们的子视图的布局完全不同。事实上,如果您使用默认的 UITableViewCell 样式,这正是发生的情况。例如,“默认”样式和“字幕”样式都由相同的 UITableViewCell 类表示。

这一点很重要:单元格的与特定的视图层次结构没有一对一的关联。视图层次结构完全由向该特定控制器注册的原型单元中的内容决定。

另请注意,细胞的重复使用标识符未在某些全球细胞药房中注册。重用标识符仅在单个 UITableView 实例的上下文中使用。


有了这些信息,让我们看看您的上述尝试中发生了什么。

在控制器#1中,添加了一个原型单元,将类设置为我的
UITableViewCell子类,设置重用id,添加标签和连线
他们到班级的销售点。在控制器 #2 中,添加一个空的
原型单元,将其设置为相同的类并像以前一样重用 id。什么时候
它运行时,当单元格显示在中时,标签永远不会出现
控制器#2。在控制器 #1 中工作正常。

这是预料之中的。虽然两个单元格具有相同的类,但传递到控制器 #2 中的单元格的视图层次结构完全没有子视图。所以你得到了一个空单元格,这正是你在原型中放置的内容。

在不同的 NIB 中设计每种单元类型并连接到
适当的细胞类别。在故事板中,添加了一个空的原型单元
并设置其类并重用 id 以引用我的单元类。在
控制器的 viewDidLoad 方法,注册了那些 NIB 文件
重复使用 ID。显示时,两个控制器中的单元格都是空的,就像
原型。

同样,这是预期的。重用标识符不在故事板场景或笔尖之间共享,因此所有这些不同的单元具有相同的重用标识符这一事实是没有意义的。从表格视图返回的单元格的外观将与故事板该场景中的原型单元格相匹配。

不过,这个解决方案已经很接近了。正如您所指出的,您可以仅以编程方式调用 -[UITableView registerNib:forCellReuseIdentifier:],传递包含单元格的 UINib,然后您将返回同一单元格。 (这并不是因为原型“覆盖”了笔尖;您只是没有在桌面视图中注册笔尖,所以它仍在查看嵌入故事板中的笔尖。)不幸的是,这种方法有一个缺陷 -无法将故事板连接到独立笔尖中的单元格。

将两个控制器中的原型保留为空并设置类和重用 ID
到我的细胞班。完全用代码构建单元格的 UI。细胞
在所有控制器中都能完美工作。

自然。希望这并不令人意外。


所以,这就是它不起作用的原因。您可以在独立的笔尖中设计单元格,并在多个故事板场景中使用它们;您目前无法将故事板连接到这些单元格。但希望您在阅读本文的过程中学到了一些东西。

As I understand it, you want to:

  1. Design a cell in IB which can be used in multiple storyboard scenes.
  2. Configure unique storyboard segues from that cell, depending on the scene the cell is in.

Unfortunately, there is currently no way to do this. To understand why your previous attempts didn't work, you need to understand more about how storyboards and prototype table view cells work. (If you don't care about why these other attempts didn't work, feel free to leave now. I've got no magical workarounds for you, other than suggesting that you file a bug.)

A storyboard is, in essence, not much more than a collection of .xib files. When you load up a table view controller that has some prototype cells out of a storyboard, here's what happens:

  • Each prototype cell is actually its own embedded mini-nib. So when the table view controller is loading up, it runs through each of the prototype cell's nibs and calls -[UITableView registerNib:forCellReuseIdentifier:].
  • The table view asks the controller for the cells.
  • You probably call -[UITableView dequeueReusableCellWithIdentifier:]
  • When you request a cell with a given reuse identifier, it checks whether it has a nib registered. If it does, it instantiates an instance of that cell. This is composed of the following steps:

    1. Look at the class of the cell, as defined in the cell's nib. Call [[CellClass alloc] initWithCoder:].
    2. The -initWithCoder: method goes through and adds subviews and sets properties that were defined in the nib. (IBOutlets probably get hooked up here as well, though I haven't tested that; it may happen in -awakeFromNib)
  • You configure your cell however you want.

The important thing to note here is there is a distinction between the class of the cell and the visual appearance of the cell. You could create two separate prototype cells of the same class, but with their subviews laid out completely differently. In fact, if you use the default UITableViewCell styles, this is exactly what's happening. The "Default" style and the "Subtitle" style, for example, are both represented by the same UITableViewCell class.

This is important: The class of the cell does not have a one-to-one correlation with a particular view hierarchy. The view hierarchy is determined entirely by what's in the prototype cell that was registered with this particular controller.

Note, as well, that the cell's reuse identifier was not registered in some global cell dispensary. The reuse identifier is only used within the context of a single UITableView instance.


Given this information, let's look at what happened in your above attempts.

In Controller #1, added a prototype cell, set the class to my
UITableViewCell subclass, set the reuse id, added the labels and wired
them to the class's outlets. In Controller #2, added an empty
prototype cell, set it to the same class and reuse id as before. When
it runs, the labels never appear when the cells are shown in
Controller #2. Works fine in Controller #1.

This is expected. While both cells had the same class, the view hierarchy that was passed to the cell in Controller #2 was entirely devoid of subviews. So you got an empty cell, which is exactly what you put in the prototype.

Designed each cell type in a different NIB and wired up to the
appropriate cell class. In storyboard, added an empty prototype cell
and set its class and reuse id to refer to my cell class. In
controllers' viewDidLoad methods, registered those NIB files for the
reuse id. When shown, cells in both controllers were empty like the
prototype.

Again, this is expected. The reuse identifier is not shared between storyboard scenes or nibs, so the fact that all of these distinct cells had the same reuse identifier was meaningless. The cell you get back from the tableview will have an appearance that matches the prototype cell in that scene of the storyboard.

This solution was close, though. As you noted, you could just programmatically call -[UITableView registerNib:forCellReuseIdentifier:], passing the UINib containing the cell, and you'd get back that same cell. (This isn't because the prototype was "overriding" the nib; you simply hadn't registered the nib with the tableview, so it was still looking at the nib embedded in the storyboard.) Unfortunately, there's a flaw with this approach — there's no way to hook up storyboard segues to a cell in a standalone nib.

Kept prototypes in both controllers empty and set class and reuse id
to my cell class. Constructed the cells' UI entirely in code. Cells
work perfectly in all controllers.

Naturally. Hopefully, this is unsurprising.


So, that's why it didn't work. You can design your cells in standalone nibs and use them in multiple storyboard scenes; you just can't currently hook up storyboard segues to those cells. Hopefully, though, you've learned something in the process of reading this.

你的他你的她 2025-01-12 10:15:31

尽管 BJ Homer 的回答很好,但我觉得我有一个解决方案。就我的测试而言,它有效。

概念:为 xib 单元创建自定义类。您可以在那里等待触摸事件并以编程方式执行转场。现在我们需要的是对执行 Segue 的控制器的引用。我的解决方案是在 tableView:cellForRowAtIndexPath: 中设置它。

示例

我有一个 DetailedTaskCell.xib ,其中包含一个我想在多个表格视图中使用的表格单元格:

DetailedTaskCell.xib

该单元有一个自定义类 TaskGuessTableCell

在此处输入图像描述

这就是奇迹发生的地方。

// TaskGuessTableCell.h
#import <Foundation/Foundation.h>

@interface TaskGuessTableCell : UITableViewCell
@property (nonatomic, weak) UIViewController *controller;
@end

// TashGuessTableCell.m
#import "TaskGuessTableCell.h"

@implementation TaskGuessTableCell

@synthesize controller;

- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
    NSIndexPath *path = [controller.tableView indexPathForCell:self];
    [controller.tableView selectRowAtIndexPath:path animated:NO scrollPosition:UITableViewScrollPositionNone];
    [controller performSegueWithIdentifier:@"FinishedTask" sender:controller];
    [super touchesEnded:touches withEvent:event];
}

@end

我有多个 Segue,但它们都具有相同的名称:“FinishedTask”。如果您需要在这里灵活一些,我建议添加另一个属性。

ViewController 看起来像这样:

// LogbookViewController.m
#import "LogbookViewController.h"
#import "TaskGuessTableCell.h"

@implementation LogbookViewController

- (void)viewDidLoad
{
    [super viewDidLoad]

    // register custom nib
    [self.tableView registerNib:[UINib nibWithNibName:@"DetailedTaskCell" bundle:[NSBundle mainBundle]] forCellReuseIdentifier:@"DetailedTaskCell"];
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    TaskGuessTableCell *cell;

    cell = [tableView dequeueReusableCellWithIdentifier:@"DetailedTaskCell"];
    cell.controller = self; // <-- the line that matters
    // if you added the seque property to the cell class, set that one here
    // cell.segue = @"TheSegueYouNeedToTrigger";
    cell.taskTitle.text  = [entry title];
    // set other outlet values etc. ...

    return cell;
}

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
    if([[segue identifier] isEqualToString:@"FinishedTask"])
    {
        // do what you have to do, as usual
    }

}

@end

可能有更优雅的方法来实现相同的目的,但是 - 它有效! :)

In spite of the great answer by BJ Homer I feel like I have a solution. As far as my testing goes, it works.

Concept: Create a custom class for the xib cell. There you can wait for a touch event and perform the segue programmatically. Now all we need is a reference to the controller performing the Segue. My solution is to set it in tableView:cellForRowAtIndexPath:.

Example

I have a DetailedTaskCell.xib containing a table cell which I'd like to use in multiple table views:

DetailedTaskCell.xib

There is a custom class TaskGuessTableCell for that cell:

enter image description here

This is where the magic happens.

// TaskGuessTableCell.h
#import <Foundation/Foundation.h>

@interface TaskGuessTableCell : UITableViewCell
@property (nonatomic, weak) UIViewController *controller;
@end

// TashGuessTableCell.m
#import "TaskGuessTableCell.h"

@implementation TaskGuessTableCell

@synthesize controller;

- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
    NSIndexPath *path = [controller.tableView indexPathForCell:self];
    [controller.tableView selectRowAtIndexPath:path animated:NO scrollPosition:UITableViewScrollPositionNone];
    [controller performSegueWithIdentifier:@"FinishedTask" sender:controller];
    [super touchesEnded:touches withEvent:event];
}

@end

I have multiple Segues but they all have the same name: "FinishedTask". If you need to be flexible here, I suggest to add another property.

The ViewController looks like this:

// LogbookViewController.m
#import "LogbookViewController.h"
#import "TaskGuessTableCell.h"

@implementation LogbookViewController

- (void)viewDidLoad
{
    [super viewDidLoad]

    // register custom nib
    [self.tableView registerNib:[UINib nibWithNibName:@"DetailedTaskCell" bundle:[NSBundle mainBundle]] forCellReuseIdentifier:@"DetailedTaskCell"];
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    TaskGuessTableCell *cell;

    cell = [tableView dequeueReusableCellWithIdentifier:@"DetailedTaskCell"];
    cell.controller = self; // <-- the line that matters
    // if you added the seque property to the cell class, set that one here
    // cell.segue = @"TheSegueYouNeedToTrigger";
    cell.taskTitle.text  = [entry title];
    // set other outlet values etc. ...

    return cell;
}

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
    if([[segue identifier] isEqualToString:@"FinishedTask"])
    {
        // do what you have to do, as usual
    }

}

@end

There might be more elegant ways to achieve the same but - it works! :)

和我恋爱吧 2025-01-12 10:15:31

我一直在寻找这个,并找到了 Richard Venable 的这个答案。这对我有用。

iOS 5 在 UITableView 上包含了一个新方法:registerNib:forCellReuseIdentifier:

要使用它,请将 UITableViewCell 放入笔尖中。它必须是唯一的根
笔尖中的物体。

您可以在加载 tableView 后注册笔尖,然后当您
调用 dequeueReusableCellWithIdentifier:使用单元标识符,它
将从笔尖拉出它,就像您使用故事板一样
原型电池。

I was looking for this and I found this answer by Richard Venable. It works for me.

iOS 5 includes a new method on UITableView: registerNib:forCellReuseIdentifier:

To use it, put a UITableViewCell in a nib. It has to be the only root
object in the nib.

You can register the nib after loading your tableView, then when you
call dequeueReusableCellWithIdentifier: with the cell identifier, it
will pull it from the nib, just like if you had used a Storyboard
prototype cell.

三人与歌 2025-01-12 10:15:31

BJ Homer 对正在发生的事情给出了很好的解释。

从实际的角度来看,我想补充一点,鉴于您不能将单元格作为 xib 并连接 segues,最好的选择是将单元格作为 xib - 转换比跨多个位置的单元格布局和属性更容易维护,无论如何,您的 Segues 可能与不同的控制器不同。您可以直接定义从表视图控制器到下一个控制器的segue,并在代码中执行它。 。

进一步注意的是,将单元格作为单独的 xib 文件可以防止您将任何操作等直接连接到表视图控制器(无论如何,我还没有解决这个问题 - 您不能将文件的所有者定义为任何有意义的东西) )。我正在通过定义单元格的表视图控制器应符合的协议并将控制器添加为弱属性(类似于委托)来解决此问题,在 cellForRowAtIndexPath 中。

BJ Homer has given an excellent explanation of what is going on.

From a practical standpoint I'd add that, given you can't have cells as xibs AND connect segues, the best one to choose is having the cell as a xib - transitions are far easier to maintain than cell layouts and properties across multiple places, and your segues are likely to be different from your different controllers anyway. You can define the segue directly from your table view controller to the next controller, and perform it in code. .

A further note is that having your cell as a separate xib file prevents you being able to connect any actions etc. directly to the table view controller (I haven't worked this out, anyway - you can't define file's owner as anything meaningful). I am working around this by defining a protocol that the cell's table view controller is expected to conform to and adding the controller as a weak property, similar to a delegate, in cellForRowAtIndexPath.

番薯 2025-01-12 10:15:31

Swift 3

BJ Homer 给出了很好的解释,它帮助我理解了这个概念。为了使自定义单元在 Storyboard 中可重用(可以在任何 TableViewController 中使用),我们必须混合 Storyboard 和 xib 方法。假设我们有一个名为 CustomCell 的单元格,它将在 TableViewControllerOneTableViewControllerTwo 中使用。我正在分步骤进行。
1. 文件>新的>单击文件>选择 Cocoa Touch 类别 >单击“下一步”>给出您的班级名称(例如 CustomCell)>选择子类为 UITableVieCell >勾选同时创建 XIB 文件复选框并按下一步。
2.根据需要自定义单元格,并在单元格的属性检查器中设置标识符,这里我们设置为CellIdentifier。该标识符将在您的 ViewController 中用于识别和重用 Cell。
3. 现在我们只需在 ViewController viewDidLoad注册此单元即可。不需要任何初始化方法。
4. 现在我们可以在任何 tableView 中使用这个自定义单元格。

在 TableViewControllerOne 中

let reuseIdentifier = "CellIdentifier"

override func viewDidLoad() {
super.viewDidLoad()
tableView.register(UINib(nibName: "CustomCell", bundle: nil), forCellReuseIdentifier: reuseIdentifier)
} 

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier:reuseIdentifier, for: indexPath) as! CustomCell
    return cell!
}

Swift 3

BJ Homer gave an excellent explanation, It helps me understand the concept. To make a custom cell reusable in storyboard, which can be used in any TableViewController we have to mix the Storyboard and xib approach. Suppose we have a cell named as CustomCell which is to be used in the TableViewControllerOne and TableViewControllerTwo. I am making it in steps.
1. File > New > Click File > Select Cocoa Touch Class > click Next > Give Name Of your class(for example CustomCell) > select Subclass as UITableVieCell > Tick the also create XIB file checkbox and press Next.
2. Customize the cell as you want and set the identifier in attribute inspector for cell, here we ll set as CellIdentifier. This identifier will be used in your ViewController to identify and reuse the Cell.
3. Now we just have to register this cell in our ViewController viewDidLoad. No need of any initialization method.
4. Now we can use this custom cell in any tableView.

In TableViewControllerOne

let reuseIdentifier = "CellIdentifier"

override func viewDidLoad() {
super.viewDidLoad()
tableView.register(UINib(nibName: "CustomCell", bundle: nil), forCellReuseIdentifier: reuseIdentifier)
} 

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier:reuseIdentifier, for: indexPath) as! CustomCell
    return cell!
}
抱猫软卧 2025-01-12 10:15:31

我找到了一种为同一 VC 加载单元的方法,未针对转场进行测试。这可能是在单独的笔尖中创建单元格的一种解决方法。

假设您有一个 VC 和 2 个表,并且您想要在故事板中设计一个单元格并在两个表中使用它。

(例如:一个表格和一个带有 UISearchController 的搜索字段,其中包含一个结果表格,并且您希望在两者中使用相同的单元格)

当控制器要求单元格时,执行以下操作:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString * identifier = @"CELL_ID";

    ContactsCell *cell = [self.YOURTABLEVIEW dequeueReusableCellWithIdentifier:identifier];
  // Ignore the "tableView" argument
}

在这里您可以从情节提要中获得单元格

I found a way to load the cell for the same VC, not tested for the segues. This could be a workaround for creating the cell in a separate nib

Let's say that you have one VC and 2 tables and you want to design a cell in storyboard and use it in both tables.

(ex: a table and a search field with a UISearchController with a table for results and you want to use the same Cell in both)

When the controller asks for the cell do this:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString * identifier = @"CELL_ID";

    ContactsCell *cell = [self.YOURTABLEVIEW dequeueReusableCellWithIdentifier:identifier];
  // Ignore the "tableView" argument
}

And here you have your cell from the storyboard

记忆之渊 2025-01-12 10:15:31

如果我正确理解你的问题,这相当简单。在故事板中创建一个 UIViewController 来保存原型单元并创建一个从故事板加载自身的静态共享实例。要处理视图控制器 Segue,请在表视图委托 didSelectRow 上使用手动 Segue 出口和触发器(手动 Segue 出口是故事板中视图控制器顶部的中间图标,位于“First Responder”之间”和“退出”)。

XCode 12.5、iOS 13.6

// A cell with a single UILabel

class UILabelCell: UITableViewCell {
    @IBOutlet weak var label: UILabel!
}

// A cell with a signle UISwitch

class UISwitchCell: UITableViewCell {
    @IBOutlet weak var uiSwitch: UISwitch!
}


// The TableViewController to hold the prototype cells.    

class CellPrototypeTableViewController: UITableViewController {
    
    // Loads the view controller from the storyboard
    
    static let shared: CellPrototypeTableViewController = {
        let storyboard = UIStoryboard(name: "Main", bundle: nil)
        let viewController = storyboard.instantiateViewController(withIdentifier: "cellProtoypeVC") as! CellPrototypeTableViewController
        viewController.loadViewIfNeeded()  // Make sure to force view controller to load the view!
        return viewController
    }()

    
    // Helper methods to deque the cells
    
    func dequeUILabeCell() -> UILabelCell {
        let cell = self.tableView.dequeueReusableCell(withIdentifier: "uiLabelCell") as! UILabelCell
        return cell
    }
    
    func dequeUISwitchCell() -> UISwitchCell {
        let cell = self.tableView.dequeueReusableCell(withIdentifier: "uiSwitchCell") as! UISwitchCell
        return cell
    }
}

使用:

class MyTableViewController: UITableViewController {
    
    override func numberOfSections(in tableView: UITableView) -> Int {
        return 1
    }
    
    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return 2
    }
    
    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        
        // Dequeue the cells from the shared instance
        
        switch indexPath.row {
        case 0:
            let uiLabelCell = CellPrototypeTableViewController.shared.dequeUILabeCell()
            uiLabelCell.label.text = "Hello World"
            return uiLabelCell
        case 1:
            let uiSwitchCell = CellPrototypeTableViewController.shared.dequeUISwitchCell()
            uiSwitchCell.uiSwitch.isOn = false
            return uiSwitchCell
        default:
            fatalError("IndexPath out of bounds")
        }
    }
    
    // Handling Segues
    
    override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        switch indexPath.row {
        case 0: self.performSegue(withIdentifier: "first", sender: nil)
        case 1: self.performSegue(withIdentifier: "second", sender: nil)
        default:
            fatalError("IndexPath out of bounds")
        }
    }
}

If I understand your question correctly, this is fairly easy. Create a UIViewController in your storyboard that will hold your prototype cells and create a static shared instance that loads itself from the storyboard. To handle view controller segues, use the manual segue outlet and trigger on table view delegate didSelectRow (the manual segue outlet is the middle icon at the top of the view controller in the storyboard, in between 'First Responder' and 'Exit').

XCode 12.5, iOS 13.6

// A cell with a single UILabel

class UILabelCell: UITableViewCell {
    @IBOutlet weak var label: UILabel!
}

// A cell with a signle UISwitch

class UISwitchCell: UITableViewCell {
    @IBOutlet weak var uiSwitch: UISwitch!
}


// The TableViewController to hold the prototype cells.    

class CellPrototypeTableViewController: UITableViewController {
    
    // Loads the view controller from the storyboard
    
    static let shared: CellPrototypeTableViewController = {
        let storyboard = UIStoryboard(name: "Main", bundle: nil)
        let viewController = storyboard.instantiateViewController(withIdentifier: "cellProtoypeVC") as! CellPrototypeTableViewController
        viewController.loadViewIfNeeded()  // Make sure to force view controller to load the view!
        return viewController
    }()

    
    // Helper methods to deque the cells
    
    func dequeUILabeCell() -> UILabelCell {
        let cell = self.tableView.dequeueReusableCell(withIdentifier: "uiLabelCell") as! UILabelCell
        return cell
    }
    
    func dequeUISwitchCell() -> UISwitchCell {
        let cell = self.tableView.dequeueReusableCell(withIdentifier: "uiSwitchCell") as! UISwitchCell
        return cell
    }
}

Use:

class MyTableViewController: UITableViewController {
    
    override func numberOfSections(in tableView: UITableView) -> Int {
        return 1
    }
    
    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return 2
    }
    
    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        
        // Dequeue the cells from the shared instance
        
        switch indexPath.row {
        case 0:
            let uiLabelCell = CellPrototypeTableViewController.shared.dequeUILabeCell()
            uiLabelCell.label.text = "Hello World"
            return uiLabelCell
        case 1:
            let uiSwitchCell = CellPrototypeTableViewController.shared.dequeUISwitchCell()
            uiSwitchCell.uiSwitch.isOn = false
            return uiSwitchCell
        default:
            fatalError("IndexPath out of bounds")
        }
    }
    
    // Handling Segues
    
    override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        switch indexPath.row {
        case 0: self.performSegue(withIdentifier: "first", sender: nil)
        case 1: self.performSegue(withIdentifier: "second", sender: nil)
        default:
            fatalError("IndexPath out of bounds")
        }
    }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文