У меня есть общая функция, которая вызывает веб-сервис и сериализует ответ JSON обратно на объект.
class func invokeService<T>(service: String, withParams params: Dictionary<String, String>, returningClass: AnyClass, completionHandler handler: ((T) -> ())) {
/* Construct the URL, call the service and parse the response */
}
То, что я пытаюсь сделать, является эквивалентом этого кода Java
public <T> T invokeService(final String serviceURLSuffix, final Map<String, String> params,
final Class<T> classTypeToReturn) {
}
- Правильная ли подпись моего метода для того, что я пытаюсь выполнить?
- Более конкретно,
AnyClass
правильно ли указывать в качестве типа параметра? - При вызове метода я
MyObject.self
передаю значение returningClass, но получаю ошибку компиляции «Невозможно преобразовать тип выражения« () »в тип« Строка »
CastDAO.invokeService("test", withParams: ["test" : "test"], returningClass: CityInfo.self) { cityInfo in /*...*/
}
Редактировать:
Я попытался использовать object_getClass
, как уже упоминалось holex, но теперь я получаю:
ошибка: «Тип« CityInfo.Type »не соответствует протоколу« AnyObject »»
Что нужно сделать, чтобы соответствовать протоколу?
class CityInfo : NSObject {
var cityName: String?
var regionCode: String?
var regionName: String?
}
swift
generics
type-inference
Жан-Франсуа Ганьон
источник
источник
CastDAO.invokeService("test", withParams: ["test" : "test"]) { (ci:CityInfo) in }
Ответы:
Вы подходите к этому неправильно: в Swift, в отличие от Objective-C, классы имеют специфические типы и даже имеют иерархию наследования (то есть, если класс
B
наследуется отA
, тоB.Type
также наследуется отA.Type
):Вот почему вы не должны использовать
AnyClass
, если вы действительно хотите разрешить любой класс. В этом случае правильный тип будетT.Type
, потому что он выражает связь междуreturningClass
параметром и параметром замыкания.Фактически, использование его вместо
AnyClass
позволяет компилятору правильно выводить типы в вызове метода:Теперь существует проблема создания экземпляра
T
для передачиhandler
: если вы попытаетесь запустить код прямо сейчас, компилятор будет жаловаться, чтоT
его нельзя скомпилировать()
. И по праву так:T
должно быть явно ограничено, чтобы требовать, чтобы он реализовал определенный инициализатор.Это можно сделать с помощью протокола, подобного следующему:
Тогда вам нужно только изменить общие ограничения
invokeService
с<T>
на на<T: Initable>
.Наконечник
Если вы получаете странные ошибки, такие как «Невозможно преобразовать тип выражения« () »в тип« Строка », часто бывает полезно переместить каждый аргумент вызова метода в его собственную переменную. Это помогает сузить код, вызывающий ошибку, и выявить проблемы с выводом типа:
Теперь есть две возможности: ошибка перемещается к одной из переменных (что означает, что там находится неправильная часть), или вы получаете загадочное сообщение типа «Невозможно преобразовать тип выражения
()
в тип($T6) -> ($T6) -> $T5
».Причиной последней ошибки является то, что компилятор не может определить типы того, что вы написали. В этом случае проблема заключается в том, что
T
он используется только в параметре замыкания, а переданное замыкание не указывает какого-либо конкретного типа, поэтому компилятор не знает, какой тип выводить. Изменяя типreturningClass
для включения,T
вы даете компилятору способ определить универсальный параметр.источник
T
используется для выражения отношения междуreturningClass
объектом и объектом, переданнымcompletionHandler
. ЕслиInitiable.Type
используется, это отношение теряется.func somefunc<U>()
Вы можете получить класс
AnyObject
через этот путь:Swift 3.x
Swift 2.x
и вы можете передать его как параметр позже, если хотите.
источник
self.dynamicType
У меня есть похожий случай использования в swift5:
источник
Static method … requires that 'MyDecodable.Type' conform to 'Decodable'
. Не могли бы вы обновить свой ответ, чтобы привести примерloadItem
?.Type
и.self
(тип и метатип).Используйте
obj-getclass
:Предполагая, что я - объект информации города.
источник
Swift 5
Не совсем та же ситуация, но у меня была похожая проблема. Что мне наконец помогло, так это:
Затем вы можете вызвать его внутри экземпляра указанного класса следующим образом:
Надеюсь, это поможет кому-то в моей ситуации.
источник