2016-02-05 4 views
1

У меня есть протокол под названием ContentService, который предназначен для раскрытия общей функциональности для чтения данных из различных API REST. Каждая реализация ContentService будет выполнять механики, требуемые этим конкретным API.Параметр типа обобщенного метода Swift при реализации метода протокола

protocol ContentService {  
    func loadNextPage<T>(pageStartId: T) -> [Datum] 
    //Other methods... 
} 

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

class ServiceA : ContentService { 

    func loadNextPage<Int>(pageStartId: Int) -> [Datum] { 
     //Do something with pageStartId typed as an Int 
     return posts 
    } 
} 

class ServiceB : ContentService { 
    func loadNextPage<NSDate>(pageStartId: NSDate) -> [Datum] { 
     //Do something with pageStartId typed as an NSDate 
     return posts 
    } 
} 

ПРИМЕЧАНИЕ, что я 'm, определяющий параметр типа в определении моих типов реализации (ServiceA, ServiceB), потому что они специфичны для этой службы. Я ожидаю, что любой экземпляр этих классов будет иметь метод с сигнатурой loadNextPage(pageStartId: X) -> [Post], где X является конкретным типом, поставляемым для T при реализации метода.

Для загрузки страницы данных из API, я бы таким образом использовать что-то вроде этого:

let apiA = ServiceA() 
let apiB = ServiceB() 

let dataA = apiA.loadNextPage(1234) 
let dataB = apiB.loadNextPage(NSDate()) 

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

let dataA = apiA.loadNextPage("Anything works here.") 

Поэтому метод ServiceA в loadNextPage() не ограничиваясь Int параметров. Кроме того, в определениях метода loadNextPage(), хотя параметр pageStartId, кажется, имеет ожидаемый тип при проверке его в Xcode, я не могу использовать никаких операторов или методов, которые обычно доступны для этого типа. Например, в реализации ServiceA я не могу сделать let newId = pageStartId + 5, хотя pageStartId должен быть Int.

Два вопроса:

1) Очевидно, что я что-то недоразумение об общих методах в Swift и хотел бы знать, почему эта модель не может быть использована.

2) Если у кого-то есть умное решение для достижения желания, я пытаюсь выше, я бы хотел это знать.

ответ

4

Ваш протокол

protocol ContentService {  
    func loadNextPage<T>(pageStartId: T) -> [Datum] 
    //Other methods... 
} 

требует шаблонного метода loadNextPage и

func loadNextPage<Int>(pageStartId: Int) -> [Datum] { 
    //Do something with pageStartId typed as an Int 
    return posts 
} 

точно, что: Обобщенный метод, где заполнитель происходит с иметь имя Int. Внутри метода Int относится к этому типу заполнителя и шкуры глобальный тип Swift Int.Эквивалентное определение будет

func loadNextPage<FOO>(pageStartId: FOO) -> [Datum] { 
    //Do something with pageStartId typed as an Int 
    return posts 
} 

То, что вы, вероятно, хотите, чтобы определить протокол с связанного типаT:

protocol ContentService { 
    associatedtype T 
    func loadNextPage(pageStartId: T) -> [Datum] 
    //Other methods... 
} 

и класс, который принимает этот протокол с T == Int:

class ServiceA : ContentService { 

    func loadNextPage(pageStartId: Int) -> [Datum] { 
     let newId = pageStartId + 5 // <-- This compiles now! 
     //Do something with pageStartId typed as an Int 
     return posts 
    } 
} 

let dataA = apiA.loadNextPage(1234) 

компилирует, но

let dataA2 = apiA.loadNextPage("Anything works here.") 
// error: cannot convert value of type 'String' to expected argument type 'Int' 

не, как ожидалось.

+0

Работает отлично. Благодаря! – Dragonspell

+0

Хорошо. Так что это работает как указано, но при объявлении свойства типа ContentService в другом классе я получаю следующую ошибку: «Протокол« ContentService »может использоваться только как общее ограничение, потому что он имеет связанные требования типа». Хотя я буду назначать экземпляр конкретного класса для этого var при инициализации, я хотел бы, чтобы мое объявление свойства имело тип протокола, чтобы оно могло ссылаться на любой из моих классов ContentService. – Dragonspell

+0

@Dragonspell: Если я правильно помню, это известное ограничение Swift в настоящее время, вы не можете объявить переменную типа протокола, если у протокола есть связанный тип (вы должны найти некоторые вопросы и ответы относительно этого сообщения об ошибке). К сожалению, у меня нет времени для более детального ответа. –

Смежные вопросы