@IBInspectable为类设置类型别名



我正在尝试构建一个以 RealmResults<Object>为模型的通用UITableViewController

这些是我的简化类:

领域对象:

import RealmSwift
class Test: Object {
dynamic var name = ""
}

表视图单元格:

import UIKit
import RealmSwift
class RealmCell: UITableViewCell {
typealias Entity = Test // from above
var object: Entity? {
didSet {
if let object = object {
textLabel?.text = object.name
}
}
}
}

表视图控制器:

import UIKit
import RealmSwift
class RealmTableViewController: UITableViewController {
typealias TableCell = RealmCell // From example above            
var objects = try! Realm().objects(TableCell.Entity.self) {
didSet { tableView.reloadData() }
}
// MARK: - UITableViewDataSource
override func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return objects.count
}
override func tableView(_ tableView: UITableView,
cellForRowAt indexPath: IndexPath)
-> UITableViewCell {
let cell =
tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! TableCell
cell.object = objects[indexPath.row]
return cell
}
}

我想不出一种方法可以使表单元格类型别名@IBInspectable。我一直在尝试使用NSClassFromString(_:)但没有成功。

希望有人能帮忙。

如果我理解正确,您基本上希望能够在界面生成器中指定实体名称,是吗? 即您希望能够基本上从检查器中选择您的自定义类?

如果是这样,那么不幸的是,这不可能直接实现。 @IBInspectable只能与特定类型一起使用,如下所述:

可以将 IBInspectable 属性添加到类声明、类扩展或类型类别中的任何属性:布尔值、整数或浮点数、字符串、本地化字符串、矩形、点、大小、颜色、范围和 nil。

但是,您可以将字符串属性指定为 IBInspectable(具有有意义的默认值),并在初始值设定项中从中扣除类。这将留下错误的可能性,即错别字,但它仍然可以工作。

另请参阅此答案。

评论后编辑: 在这种情况下,恐怕这是不可能的(至少据我所知,可能有一些我不知道的深层次黑客,但那可能会像地狱一样丑陋)。 问题是 IB 中指定的内容只能在运行时计算,而类型别名是在编译时定义的东西。

我认为您基本上想要的只是每个单元格类应该具有的功能的协议(以及通用视图控制器所依赖的功能)。你甚至不需要类型别名,因为协议本身就是一个类型。

然后可以根据IBInspectable-ed 字符串选择具体的单元格类,协议甚至可以为此定义一种方法。

根据方案的详细信息,您甚至可以为所有单元格编写一个通用超类。一个已经采用(部分)协议(在这种情况下,您甚至可以省略协议,但我建议使用一个以提高可读性)。

这显然假设您拥有为通用单元格定义的视图控制器所需的所有功能,但这是您在任何情况下面临的问题(即使您可以使用在运行时定义的类型别名)。


我看了你的示例代码后第二次编辑

好的,我又看了一遍,希望现在可以更好地解释这一点。不幸的是,我不能直接添加到您的存储库中,因为它无法编译(我缺少 Realm 框架/pod,即使我补充说我可能什么也赢不了,因为我不知道你到底用它做什么)。

正如评论中所说,我会说你不需要任何进一步的IBInspectable属性来设置类。这应该已经发生在您的情节提要中,即您应该将给定原型单元格的类值设置为您拥有的具体单元格类之一。但是,泛型RealmTableViewController不需要知道该类。如果我理解正确,您似乎想给它这方面的知识,可能会让它根据其具体特征正确准备细胞。不要那样做(我一会儿会讲到你想在viewDidLoad做什么)。相反,定义一个所有细胞都采用并且RealmTableViewController知道的协议。在tableView(_:cellForRowAt:)方法中,在将单元取消排队时,您可以在as! ...部分中使用此协议。该协议应定义每个具体类应实现的准备方法,然后在此时由RealmTableViewController调用该方法。

这样,您的表视图控制器保持通用,它实际上不知道它显示的单元格的任何内容,这就是事情的意图。

现在谈谈你(我认为)面临的问题:你想让控制器知道它使用哪种原型单元,这样它也可以准备特定的东西(例如,你也可以外包到协议中)。这是有问题的,因为您基本上是在尝试构建表视图控制器的核心方面:它能够同时处理不同类型的单元格。我从您的其他代码中得出结论,viewDidLoadobjects属性,最终似乎也取决于单元格的类。这与表架构本身的设计相冲突,这不仅仅是一个语法问题。但是,有一个解决方案:另一个协议,加上具体单元类的"伴侣"类。

对于您拥有的每个单元类,定义相应的类来处理您的视图控制器需要执行的 Realm 操作。也许对于某些单元格,您具有相同的对象,然后相应地编写它们(新类应该有一个定义它对应于哪个单元格的属性)。定义一个所有人都采用的协议,并且至少有两种方法(也许使用更好的名称,这里已经晚了......):doControllerStuffgetCellIdentifier

然后,您的RealmTableViewController最终获得了IBInspectable。如果设置了,控制器将伴随对象实例化到单元(使用哪个具体类显然取决于 IBInspectable 的值)。如果同一个伴侣处理多个单元,则IBInspectable还必须定义将使用哪个单元,即必须正确配置伴随单元。您可以使用某种字符串约定,甚至可以编写一个工厂类,该工厂类对视图控制器隐藏具体类,并仅为其返回一个键入为协议的正确对象。

无论如何,无论您在viewDidLoad中基于到目前为止的类执行什么操作,请将其更改为doControllerStuff方法。你甚至可能有一些超类和子类,如果这在细胞/同伴中很常见,那没关系。最后,在 'tableView(_:cellForRowAt:) 方法中,您不直接使用标识符,而是向配套对象询问标识符。

不过,这里有一点需要注意:显然,您必须确保单元格标识符的接口生成器值设置正确,即它与您在视图控制器实例中设置的 IBInspectable 匹配。不过,您可以围绕此问题编写一个捕获,并使用默认单元格,只需抛出异常即可。


这已经变得相当长了,我希望这是可以理解的。我没有时间制作这个或其他东西的漂亮图形,所以如果你还有问题,我建议我们带这个去聊天。:)只要通知我,我们会的(虽然从明天开始我有点空闲)。