我正在尝试在Swift中构建一个通用的UITableViewController子类,它可以容纳任意数量的不同类型的表视图单元,而不具备任何内部知识.
要做到这一点,我正在尝试为我的模型和我的表视图单元格使用协议.模型的协议将返回我应该去的哪个单元类,并且单元的协议将返回问题的答案,例如给定模型的单元格高度应该是什么.
但是我在使协议工作时遇到问题,因为使用第二个协议我想要转到单元的类而不是它的实例.
模型的协议如下:
protocol JBSTableItemDelegate
{
func tableCellDelegate() -> JBSTableViewCellInterface
}
Run Code Online (Sandbox Code Playgroud)
细胞的协议如下:
protocol JBSTableViewCellInterface: class
{
static func registerNibsWithTableView(tableView: UITableView)
static func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath?, tableItem: JBSTableItemDelegate) -> CGFloat
static func tableView(tableView: UITableView, dequeueReusableCellWithIndexPath indexPath: NSIndexPath, tableItem: JBSTableItemDelegate, delegate: AnyObject) -> JBSTableViewCell
}
Run Code Online (Sandbox Code Playgroud)
请注意使用关键字"static".这些方法是UITableViewCell子类中的类方法,添加静态似乎是我需要做的,以验证这些类符合,或者我理解.
当我使用第一个协议时代码看起来像这样,它编译:
let tableViewCellInterface = tableItem!.tableViewCellInterface()
Run Code Online (Sandbox Code Playgroud)
它正在调用此方法(作为一个示例):
func tableViewCellInterface() -> JBSTableViewCellInterface
{
return JBSLiteratureTableViewCell.self as! JBSTableViewCellInterface
}
Run Code Online (Sandbox Code Playgroud)
这将返回单元格的类,例如"JBSLiteratureTableViewCell.self"
当我使用第二个协议时,代码看起来像这样,并且它不编译:
returnFloat = tableViewCellInterface.tableView(tableView, heightForRowAtIndexPath: indexPath, tableItem: tableItem!)
Run Code Online (Sandbox Code Playgroud)
由于之前的static关键字,它无法编译,我得到的编译器错误是:
'JBSTableViewCellInterface'没有名为'tableView'的成员
如果我从协议函数中取出静态关键字,它会编译,但是UITableViewCell子类抱怨说:
'JBSLiteratureTableViewCell'不符合协议'JBSTableViewCellInterface'
这是因为他们现在正试图确保实例方法存在,而不是这些方法.
如何使swift类符合类级别的协议,因此它可以是我的委托而不是类的某个实例?我确信我可以通过创建作为单例的协议JBSTableViewCellInterface的辅助类来解决这个问题并让它们完成工作,但我宁愿在它们的类方法中将它构建到UITableViewCell子类中.
我有一个使用关联类型的协议,如下所示:
protocol Populatable {
typealias T
func populateWith(object: T)
}
Run Code Online (Sandbox Code Playgroud)
和实现协议的类:
class DateRowType: Populatable {
func populateWith(object: NSDate) {
print(object.description)
}
}
class StringRowType : Populatable {
func populateWith(object: String) {
print(object)
}
}
Run Code Online (Sandbox Code Playgroud)
但是当我尝试投射或测试一致性时,像这样:
let drt = DateRowType()
let srt = StringRowType()
let rowTypes = [drt, srt]
let data = [NSDate(), "foo"]
for (i, p: Populatable) in enumerate(rowTypes) {
p.populateWith(data[i])
}
Run Code Online (Sandbox Code Playgroud)
我收到错误:
Protocol'Populatable'只能用作通用约束,因为它具有Self或相关类型要求
测试对象是否符合Populatable协议的正确方法是什么?
注意:尝试此操作所需的所有代码都包含在问题中,只需将代码块复制到操场中即可.
我有一个相当大的应用程序,它有很多集合视图.大多数集合视图都具有相同的数据源和流布局代表(相同的大小,边距等)的实现.我正在尝试创建一个提供UICollectionViewDataSource和UICollectionViewDelegateFlowLayout的默认实现的协议.这是我的代码.
protocol TiledCollectionView{}
extension UICollectionViewDataSource where Self: TiledCollectionView{
//default implementation of the 3 methods to load the data ...
}
extension UICollectionViewDelegateFlowLayout where Self: TiledCollectionView {
//default implementation for layout methods to set default margins etc...
}
class MyViewController: UIViewController, TiledCollectionView, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout{
// the rest of the required logic for view controller
// here I Don't implement any CollectionView methods since I have provided the default implementation already
}
Run Code Online (Sandbox Code Playgroud)
问题是,编译器抱怨MyViewController不符合UICollectionViewDataSource.这不应该是这种情况,因为我清楚地说,如果类型是TiledCollectionView,则添加默认实现.
有人可以帮忙吗?
uicollectionview swift swift-extensions swift-protocols protocol-extension
假设我们有一个Swift协议:
protocol SomeProtocol: class {
static var someString: String { get }
}
Run Code Online (Sandbox Code Playgroud)
有没有办法someString从扩展实例方法访问,像这样?
extension SomeProtocol {
public func doSomething() -> String {
return "I'm a \(someString)"
}
}
Run Code Online (Sandbox Code Playgroud)
我收到编译器错误:
静态成员'someString'不能用于'Self'类型的实例
有没有办法实现这个目标?
我经常有相对复杂的协议与associatedType约束,在泛型中使用,由CoreData类型扩展使用等.因此我经常得到错误:Type .. does not conform to protocol ....我通常可以在一段时间后弄清楚这一点,但错误信息实际上是无益的 - 通常,如果问题是方法或某事的签名中的一个小错误,则该bug需要一段时间才能找到.使用Java接口,IDE通常会报告类似的内容method ... not implemented,因此我知道要更详细地查看哪种方法.
有没有办法让Xcode报告有关协议成员的详细信息?
假设我有以下内容:
protocol P : Equatable {
var uniqueID : Int { get }
}
struct A : P {
var uniqueID = 1
}
struct B : P {
var uniqueID = 2
}
func ==<T : P>(lhs:T , rhs:T) -> Bool { return lhs.uniqueID == rhs.uniqueID }
Run Code Online (Sandbox Code Playgroud)
现在,当我写下以下内容时:
let a = A()
let b = B()
let c = a == b
Run Code Online (Sandbox Code Playgroud)
我收到错误:二元运算符'=='不能应用于'A'和'B'类型的操作数
有没有办法实现这个目标?
我试图弄清楚如何定义一个采用以下两个参数的函数:
例如,给定
protocol P { }
class C : P { } // Class, conforming to P
class D { } // Class, not conforming to P
struct E: P { } // Struct, conforming to P
Run Code Online (Sandbox Code Playgroud)
这应该编译:
register(P.self, obj: C()) // (1)
Run Code Online (Sandbox Code Playgroud)
但这些不应该编译:
register(P.self, obj: D()) // (2) D does not conform to P
register(P.self, obj: E()) // (3) E is not a class
Run Code Online (Sandbox Code Playgroud)
如果我们放弃第二个参数是类实例的条件,这很容易:
func register<T>(proto: T.Type, obj: T) {
// ... …Run Code Online (Sandbox Code Playgroud) 我想知道是否可以在Swift中完成类似java(或c ++)的事情:
我有一个协议:
protocol Prot1 {
func returnMyself() -> Prot1
}
Run Code Online (Sandbox Code Playgroud)
一个类符合协议Prot1.我可以强制函数的返回类型returnMyself()与下面的类的类型相同吗?
class MyClass: Prot1 {
public func returnMyself() -> MyClass {
return self
}
}
Run Code Online (Sandbox Code Playgroud)
可能吗?
我有快速的代码:
protocol ParentProtocol {
// stuff
}
protocol ChildProtocol: ParentProtocol {
// additional stuff
}
protocol FooProtocol {
var variable: ParentProtocol? { get }
}
class Foo:FooProtocol {
var variable: ChildProtocol?
}
Run Code Online (Sandbox Code Playgroud)
我有编译器错误:
类型'Foo'不符合协议'FooProtocol'
我知道,根据FooProtocol,变量类型必须是ParentProtocol类型.另一方面ChildProtocol继承自ParentProtocol,所以它也是一个ParentProtocol
是否有任何解决方案以这种方式使用协议继承?
我不确定这可以做到,或者甚至不推荐.
我想要实现的目标如下:
我有一个2类,classA并且classB引用了同一个UITableview实例.我想要的是负责协议classA的2个必要方法的实现UITableViewDataSource:
numberOfRowsInSectioncellForRowAt 然后我希望classB能够实现其他可选方法titleForHeaderInSection,例如.
那么如何才能classA有一些协议方法的默认实现,让我们classB成为一个可以在classB已经完成的基础上构建的类?
在某种程度上,我面临的问题如下:多个类如何成为单个数据源UITableView?
编辑:
classA将在我正在编写的库中,负责构建tableView的核心部分.classB将由第三方开发人员用于主要定制其外观.