Opaque return types 是Swift 5.1新的语言属性。它可以用于函数、方法和属性返回一些值,无需向调用API的客户端揭示该值的具体类型。返回的类型将是一些实现了协议的类型。使用此解决方案,模块API不必公开泄漏该方法的基本内部返回类型,只需使用some关键字返回协议的隐晦类型即可。在SwiftUI中,该解决方案通常用于View中返回body属性中的某些View 。
以下是Opaque return types 提供的一些基本内容,可在我们想使用Swift创建API时使用:

    1. 提供一个特定类型的协议而无需暴露具体的类型,实现更好的API封装
    1. 由于不会返回具体类型,因此使用者不用担心未来变更协议的基础类型
    1. 在运行时才返回具体类保障了基础身份识别的稳定性。同时相比直接返回具体类型,此方案也失去了一些灵活性
    1. 此方案将返回类型的权限全部移交给函数了

通过实例深入探究Opaque return types

为了更加深入的理解Opaque return type 与 协议的返回类型的不同,让我们通过一些具体例子来展示Opaque的优势

  1. 定义一个protocal
protocol MobileOS {
    associatedtype Version
    var version: Version { get }
    init(version: Version)
}
  1. 通过具体类型来实现协议
struct iOS: MobileOS {
    var version: Float
}
struct Android: MobileOS {
    var version: String
}
  1. 写个函数返回类型

(1) 直接返回协议类型会报错

func buildPreferredOS() -> MobileOS {
    return iOS(version: 13.1)
}
// Compiler ERROR 
Protocol 'MobileOS' can only be used as a generic constraint because it has Self or associated type requirements

(2) 直接返回具体类型类型没有问题

func buildPreferredOS() -> iOS {
    return iOS(version: 13.1)
}
// Build successfully

此解决方案有效,但是如您所见,API现在将具体类型泄漏给调用方。如果将来我们改变主意并将Android作为函数的返回类型返回,则将需要大量的代码重构

(3) 返回通用类型

func buildPreferredOS<T: MobileOS>(version: T.Version) -> T {
    return T(version: version)
}
let android: Android =  buildPreferredOS(version: "Jelly Bean")
let ios: iOS = buildPreferredOS(version: 5.0)

是的,这种方法很好用。但是现在,API的调用者需要提供返回函数的具体类型。如果我们真的想让调用者不必关心具体的返回类型,那么这仍然不是正确的解决方案

(4) 最优的解决方案

func buildPreferredOS() -> some MobileOS {
    return iOS(version: 13.1)
}

使用不透明的返回类型,我们最终可以将MobileOS作为函数的返回类型返回。编译器在此维护基础特定返回类型的标识,并且调用者不必知道返回类型的内部类型,只要它实现MobileOS协议即可。

Opaque return types 每次只能返回一种特定类型

func buildPreferredOS() -> some MobileOS {
   let isEven = Int.random(in: 0...100) % 2 == 0
   return isEven ? iOS(version: 13.1) : Android(version: "Pie")
}
// Compiler ERROR ?
Cannot convert return expression of type 'iOS' to return type 'some MobileOS'
func buildPreferredOS() -> some MobileOS {
   let isEven = Int.random(in: 0...100) % 2 == 0
   return isEven ? iOS(version: 13.1) : iOS(version: "13.0")
}
// Build Successfully ?

SwiftUI中Opaque Return Types的使用

struct Row: View {
    var body: some View {
        HStack {
           Text("Hello SwiftUI")
           Image(systemName: "star.fill")
        }
    }
}

如果不使用some,那么代码将无比复杂

HStack<TupleView<(Text, Image)>>

参考资料


iCloudEnd
36 声望10 粉丝

iOS & Mac OS 攻城师 (历史 & 金融 & 美食 爱好者)