![](/img/trans.png)
[英]“Type of a class which conforms to a protocol” as parameter in a method swift
[英]How to write a return type of a method as a class that conforms to a protocol + swift
我正在做一個項目,我需要使用 swift 在 iOS 中復制使用 android 開發的功能。
在 android 應用程序中,有一個地方提到了抽象 class設備中方法的返回類型,
abstract fun getDT(): Class<out DeviceType>
其中 DeviceType 本身就是另一個抽象 class。 所以我從android開發者那里聽說,在這個方法的實際實現中,它會返回一個繼承DeviceType的class,如下所示,
override fun getDT(): Class<out DeviceType> {
return type1DeviceType::class.java
}
其中 type1DeviceType 實際上繼承了 DeviceType 抽象 class 如下
public class type1DeviceType extends DeviceType {
所以在我們的 iOS 術語中,抽象 class 的等價物是協議。
所以在 iOS 中,我編寫了一個協議來代替 Android 中的抽象 class。 而對於其中抽象function的返回類型,我需要提到返回類型是符合DeviceType協議的東西。 知道如何實現這一目標嗎?
我在 swift 中嘗試了以下代碼。
public func getDT() -> DeviceTypeProtocol.Type {
return type1DeviceType as! DeviceTypeProtocol.Type
}
但是在運行時,我得到了錯誤,
Swift 運行時失敗:類型轉換失敗
你的意思是這樣的嗎?
protocol DeviceType {
func getDeviceType() -> DeviceType.Type
}
extension DeviceType {
func getDeviceType() -> DeviceType.Type { Self.self }
}
class AudioDevice: DeviceType {
func getDeviceType() -> DeviceType.Type { AudioDevice.self }
}
class Microphone: AudioDevice {
}
class Speaker: AudioDevice {
override func getDeviceType() -> DeviceType.Type { Speaker.self }
}
class VideoDevice: DeviceType {}
class Camera: VideoDevice {}
class Monitor: VideoDevice {
func getDeviceType() -> DeviceType.Type { VideoDevice.self }
}
func test() {
print(AudioDevice().getDeviceType()) // prints AudioDevice
print(Microphone().getDeviceType()) // prints AudioDevice
print(Speaker().getDeviceType()) // prints Speaker
print(VideoDevice().getDeviceType()) // prints VideoDevice
print(Camera().getDeviceType()) // prints Camera
print(Monitor().getDeviceType()) // prints VideoDevice
}
為DeviceType
定義了一個協議,該協議具有返回帶有getDeviceType
的類型的能力,該類型也是DeviceType
的類型。
您所描述的內容不需要擴展協議,但我想以任何一種方式進行演示。 它用於VideoDevice
。
所以AudioDevice
繼承了協議,並顯式定義了獲取設備類型的方法。 因為它返回的是它打印出來的AudioDevice
類型。 Microphone
繼承自AudioDevice
(不是來自DeviceType
)並且不覆蓋該方法,因此它也返回AudioDevice
。 並且Speaker
也繼承自AudioDevice
但確實覆蓋了該方法,因此返回Speaker
。
VideoDevice
更有趣一些。 它繼承了協議,但沒有明確定義所需的方法。 因此它使用具有Self.self
有趣語法的擴展。 它基本上只是意味着“返回動態自我的 static 類型的任何東西”如果這更有意義的話......這只是可能的,因為定義了協議的擴展。 刪除擴展將創建一個編譯時錯誤,讓您知道您確實需要定義該方法。 現在因為很好地定義了擴展,所以VideoDevice
已經自己打印出來了。 從VideoDevice
(而不是DeviceType
)繼承的Camera
也是如此。 然后Monitor
再次覆蓋該方法並打印出VideoDevice
而不是Monitor
。
當然,您可以將設備類別(在本例中為視頻和音頻)定義為繼承設備類型的協議。 您還可以對這些協議進行擴展。 看看這個例子:
protocol DeviceType {
func getDeviceType() -> DeviceType.Type
}
protocol AudioDevice: DeviceType { }
class Microphone: AudioDevice {
func getDeviceType() -> DeviceType.Type { Microphone.self }
}
class Speaker: AudioDevice {
func getDeviceType() -> DeviceType.Type { Speaker.self }
}
protocol VideoDevice: DeviceType { }
extension VideoDevice {
func getDeviceType() -> DeviceType.Type { Self.self }
}
class Camera: VideoDevice {
}
class Monitor: VideoDevice {
func getDeviceType() -> DeviceType.Type { Camera.self }
}
func test() {
print(Microphone().getDeviceType()) // prints Microphone
print(Speaker().getDeviceType()) // prints Speaker
print(Camera().getDeviceType()) // prints Camera
print(Monitor().getDeviceType()) // prints Camera
}
那么 Swift 協議與 Kotlin 抽象 class 不同。 更接近的比較是 Kotlin接口和 Swift 協議。
我對你的要求在這里有點困惑。 但是,根據我在這里看到的情況,這似乎是面向協議編程的一個很好的案例,它可以減少對多個嵌套抽象類或子類的需求。
我也有點困惑,為什么您需要獲取 DeviceType 的DeviceType
.... DeviceType
本身不是DeviceType
嗎?
在我看來,這樣的事情似乎要簡單得多:
interface Device {
fun doSomething()
}
interface MobileDevice: Device {
fun onTap()
}
interface DesktopDevice: Device {
fun onClick()
}
interface WearableDevice: Device {
fun onButtonPush()
}
class AndroidPhone: MobileDevice {
override fun doSomething() {
println("I'm an Android phone.")
}
override fun onTap() {
println("Tap the screen.")
}
}
class MacDesktop: DesktopDevice {
override fun doSomething() {
println("I'm a Mac desktop.")
}
override fun onClick() {
println("Click the magic mouse.")
}
}
class SmartNecklace: WearableDevice {
override fun doSomething() {
println("I'm a smart necklace.")
}
override fun onButtonPush() {
println("Help! I've fallen and I can't get up!")
}
}
可以這樣使用:
fun exampleFunction() {
val mobile = AndroidPhone()
val desktop = MacDesktop()
val wearable = SmartNecklace()
mobile.doSomething()
desktop.doSomething()
wearable.doSomething()
val devices = listOf(mobile, desktop, wearable)
devices.forEach { device ->
when (device) {
is MobileDevice -> device.onTap()
is DesktopDevice -> device.onClick()
is WearableDevice -> device.onButtonPush()
else -> println("Unknown Type.")
}
}
}
在您的 Swift 版本中,您還可以 向協議添加一些默認行為(請參閱下面的協議擴展示例)。
protocol Device {
func doSomething()
}
protocol MobileDevice: Device {
func onTap()
}
protocol DesktopDevice: Device {
func onClick()
}
protocol WearableDevice: Device {
func onButtonPush()
}
extension Device {
func doSomething() {
print("Doing default thing.")
}
}
extension WearableDevice {
func onButtonPush() {
print("Help! I've defaulted and I can't get up!")
}
}
class AndroidPhone: MobileDevice {
func onTap() {
print("Tap the screen.")
}
}
class MacDesktop: DesktopDevice {
func doSomething() {
print("I'm a Mac desktop.")
}
func onClick() {
print("Click the magic mouse.")
}
}
class SmartNecklace: WearableDevice {
func doSomething() {
print("I'm a smart necklace.")
}
}
可以這樣使用:
func exampleFunction() {
let mobile = AndroidPhone()
let desktop = MacDesktop()
let wearable = SmartNecklace()
mobile.doSomething()
desktop.doSomething()
wearable.doSomething()
let devices: Array<Device> = [mobile, desktop, wearable]
devices.forEach { device in
switch (device) {
case let device as MobileDevice:
device.onTap()
case let device as DesktopDevice:
device.onClick()
case let device as WearableDevice:
device.onButtonPush()
default:
print("Uknown type")
}
}
}
Output
Doing default thing.
I'm a Mac desktop.
I'm a smart necklace.
Tap the screen.
Click the magic mouse.
Help! I've defaulted and I can't get up!
如果你做了這樣的事情,你就已經知道 object 的類型(如 switch/when 塊所示)。 您不需要獲取設備類型的方法。 你會得到它。
如果您的問題有什么我遺漏的,請告訴我。
至於你的錯誤:
Swift runtime failure: type cast failed
如果演員表失敗,我猜type1DeviceType
是DeviceTypeProtocol
,而不是DeviceTypeProtocol.Type
。
public func getDT() -> DeviceTypeProtocol.Type {
return type1DeviceType as! DeviceTypeProtocol
}
檢查當您嘗試輸入或使用 type1DeviceType 時顯示的類型,或查看其快速幫助以查看類型。 當你到達那一點時,你認為實際的類型是什么?
我還要問,以與 Android 版本完全相同的方式執行此操作有多重要? 我總是建議正確規划跨平台,以使事情盡可能相似。 它總是有幫助的,尤其是在作為一個團隊一起調試和構建事物時。
從上面的代碼可以看出,它幾乎是准確的。 這也是我做事的方式。 但不以能夠完成工作為代價。
class type1DeviceType: DeviceTypeProtocol {
public func getDT() -> DeviceTypeProtocol.Type {
// return type1DeviceType as! DeviceTypeProtocol.Type
return type1DeviceType.self
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.