Сделайте быстрый класс совместимым с протоколом - на уровне статики / класса

Я пытаюсь создать общий подкласс UITableViewController в Swift, который будет вмещать любое количество различных типов ячеек табличного представления, не имея внутренних сведений о какой-либо из них.

Для этого я пытаюсь использовать протоколы для своих моделей и для ячеек табличного представления. Протокол для моделей вернет, к какому классу ячеек я должен перейти, а протокол для ячеек вернет ответы на такие вопросы, как, например, какой должна быть высота ячейки для данной модели.

Но у меня проблема с тем, чтобы протоколы работали, потому что со вторым протоколом я хочу перейти к классу ячейки, а не к ее экземпляру.

Протокол для моделей следующий:

protocol JBSTableItemDelegate
{
    func tableCellDelegate() -> JBSTableViewCellInterface
}

Протокол для ячеек следующий:

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
}

Обратите внимание на использование ключевого слова static. Эти методы являются методами класса в подклассах UITableViewCell, и мне кажется, что добавление static - это то, что мне нужно сделать, чтобы убедиться, что эти классы соответствуют, или я так понимаю.

Когда я использую первый протокол, код выглядит так, и он компилируется:

let tableViewCellInterface = tableItem!.tableViewCellInterface()

Он вызывает этот метод (как один из примеров):

func tableViewCellInterface() -> JBSTableViewCellInterface
{
    return JBSLiteratureTableViewCell.self as! JBSTableViewCellInterface
}

Это возвращает класс ячейки, например "JBSLiteratureTableViewCell.self"

Когда я использую второй протокол, код выглядит так, и он не компилируется:

returnFloat = tableViewCellInterface.tableView(tableView, heightForRowAtIndexPath: indexPath, tableItem: tableItem!)

Он не может быть скомпилирован из-за ранее использованного ключевого слова static, и я получаю следующую ошибку компилятора:

'JBSTableViewCellInterface' не имеет члена с именем 'tableView'

Если я уберу статические ключевые слова из функций протокола, он компилируется, но потом подклассы UITableViewCell жалуются, говоря:

'JBSLiteratureTableViewCell' не соответствует протоколу 'JBSTableViewCellInterface'

Это потому, что теперь они пытаются убедиться, что методы экземпляра существуют, а их нет.

Как сделать так, чтобы быстрый класс соответствовал протоколу на уровне класса, чтобы он мог быть моим делегатом, а не каким-то экземпляром класса? Я уверен, что смогу обойти это, создав вспомогательные классы протокола JBSTableViewCellInterface, которые являются одиночными и позволяют им выполнять работу, но я бы предпочел встроить их прямо в подклассы UITableViewCell в их методах класса.


person John Bushnell    schedule 18.04.2015    source источник
comment
Действительно? У вас есть ссылка?   -  person John Bushnell    schedule 08.07.2015


Ответы (2)


ОБНОВЛЕНО для Swift версии 2.0 и выше

Согласно ответу Грегзо, Swift 2.0+ позволяет объявлять методы как статические в определении протокола. Они должны быть удовлетворены статическими методами / методами класса в объектах, реализующих протокол.

Вы не можете удовлетворить определение протокола для метода экземпляра с помощью статического метода или наоборот, что делает это неполным ответом на вопрос выше.

Если вы хотите попробовать это, просто используйте ключевое слово static в определении вашего протокола для методов, которые вы будете реализовывать как статические методы или методы класса в ваших соответствующих объектах:

protocol InstanceVsStatic {
    func someInstanceFunc()
    static func someStaticFunc()
}

enum MyConformingEnum: InstanceVsStatic {
    case someCase

    static func someStaticFunc() {
           // code
    }
    func someInstanceFunc() {
        // code
    }
}

class MyConformingClass: InstanceVsStatic {
    class func someStaticFunc() {
           // code
    }
    func someInstanceFunc() {
        // code
    }
}

struct MyConformingStruct: InstanceVsStatic {
    static func someStaticFunc() {
           // code
    }
    func someInstanceFunc() {
        // code
    }
}

У вас может быть метод экземпляра, вызывающий статический метод / метод класса:

Это позволяет вам выполнять статический код, когда вам нужно соответствовать протоколу, требующему метода экземпляра.

struct MyConformingStruct: InstanceVsStatic {
    static func doStuffStatically(){
        // code
    }

    static func someStaticFunc() {
           // code
    }

    func someInstanceFunc() {
        MyConformingStruct.doStuffStatically()
    }
}

Swift 1.2

За исключением косвенного, как указано выше, нет возможности использовать статические (классовые) методы для соответствия протоколу в чистой быстрой версии 1.2 и ниже. Это известная ошибка / нереализованная функция: https://openradar.appspot.com/20119848

person WaterNotWords    schedule 10.06.2015
comment
Хотите знать, будет ли такая функция в будущем? - person Zigii Wong; 26.07.2015

Если функция протокола статическая, разработчик должен реализовать ее как статический метод, а если нет, как метод экземпляра:

protocol MixedProtocol
{
    static func staticFoo()
    func instanceBar()
}

class ExampleClass : MixedProtocol
{
    // implementing static func as class func is fine.
    // class funcs are overridable, not static ones
    class func staticFoo()
    {
        println( "I'm a class func" )
    }

    func instanceBar()
    {
        println( "I'm an instance func" )
    }
}

Прямого выхода нет: соответствие протоколу означает именно это, а «статичность» в значительной степени является ключевой особенностью объявления члена протокола, которую разработчики должны уважать.

person Gregzo    schedule 18.04.2015