• Swift中Typealias关键字的用法和使用场景分析
  • 发布于 2个月前
  • 513 热度
    0 评论
前言
Typealias 是 Swift 中的一种特性,它允许给现有类型定义一个新的别名。用 Typealias 命名的类型不是一个新类型,它只是特定类型的语义抽象。这个功能可以使我们的代码更具可读性,更易于维护。今天来讲讲这个关键字的一些使用场景。

1. 更好的语义
可以使用 typealias 来让一个类型具有语义,使代码更有可读性,一个非常典型的例子就是 TimeInterval 类型,很多人可能还不知道,其实 TimeInterval 并不是一个新的类型,而是 Double 类型的别名,我们点开 TimeInterval 的声明文件就可以看到了:
public typealias TimeInterval = Double
用 TimeInterval 作为 Double 的别名,就让 Double 类型有了时间间隔语义。再举个例子,Kingfisher 中有个场景是把 Int 类型命名为了 CancelToken,用来记录取消任务的 token,这种做法的目的也是让类型具有语义。
public typealias CancelToken = Int

2. 降低代码复杂度,提高可读性
可以使用 typealias 来为闭包类型、函数类型等定义别名,使代码更易于理解和维护。比如有些闭包类型比较长,每次写很不方便,就可以把它定义一个别名,比如。
typealias CompletionHandler = (_ success: Bool) -> String
  // 堆代码 duidaima.com
func doSomething(completion: CompletionHandler) {
    // 执行一些操作
    completion(true)
}

doSomething { success in
    if success {
        return "操作成功"
    } else {
        return "操作失败"
    }
}
还有一些嵌套类型的情况,导致外界访问时类型名非常长,这时候也可以用 typealias 解决,比如下边这个例子:
struct MyStruct {
    struct NestedStruct {
        struct SuperNestedStruct {
            typealias NestedType = Int
        }
    }
}

let value: MyStruct.NestedStruct.SuperNestedStruct.NestedType = 5
print(value) // 输出 "5"

typealias MyType = MyStruct.NestedStruct.SuperNestedStruct.NestedType

let newValue: MyType = 10
print(newValue) // 输出 "10"

3. 跨平台开发
使用 typealias 可以在不同平台之间提供不同的实现,从而简化跨平台开发的代码。比如你要开发一个框架,既支持 iOS 又支持 macOS,那么平台的差异会导致类型不同,比如颜色的类型,在 iOS 中为 UIColor,在 macOS 中为 NSColor,这时候为了简化开发流程就可以使用来简化。
#if os(macOS)
    typealias Color = NSColor
#elseif os(iOS) || os(tvOS) || os(watchOS)
    typealias Color = UIColor
#endif

let textColor: Color = .red
其他的控件比如 NSView、UIView,也是一样的道理。

4. 泛型类型的简化
当使用泛型类型时,可以使用 typealias 来为泛型类型定义一个更具表达力的别名,这种用法其实和第一种类似,也是提高了原类型的语义。
typealias KeyValue = Dictionary<String, Any>
func processDictionary(dict: KeyValue) {
    // 处理字典
}

let dict: KeyValue = ["name": "John", "age": 30]
processDictionary(dict: dict)
5. 简化元组
元组中如果数量过多,也会导致类型非常长,这时候除了减少元素数量之外,也可以使用 typealias 为复杂元组类型定义一个更有意义的别名,从而提高代码的可读性。以 Alamofire 为例,在做身份验证时有一段使用 typealias 为元组类型定义别名的场景:
typealias ChallengeEvaluation = (disposition: URLSession.AuthChallengeDisposition, credential: URLCredential?, error: AFError?)

open func urlSession(_ session: URLSession,
                     task: URLSessionTask,
                     didReceive challenge: URLAuthenticationChallenge,
                     completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) {
    eventMonitor?.urlSession(session, task: task, didReceive: challenge)

    let evaluation: ChallengeEvaluation
    switch challenge.protectionSpace.authenticationMethod {
    case NSURLAuthenticationMethodHTTPBasic, NSURLAuthenticationMethodHTTPDigest, NSURLAuthenticationMethodNTLM,
         NSURLAuthenticationMethodNegotiate:
        evaluation = attemptCredentialAuthentication(for: challenge, belongingTo: task)
    #if !(os(Linux) || os(Windows))
    case NSURLAuthenticationMethodServerTrust:
        evaluation = attemptServerTrustAuthentication(with: challenge)
    case NSURLAuthenticationMethodClientCertificate:
        evaluation = attemptCredentialAuthentication(for: challenge, belongingTo: task)
    #endif
    default:
        evaluation = (.performDefaultHandling, nil, nil)
    }

    if let error = evaluation.error {
        stateProvider?.request(for: task)?.didFailTask(task, earlyWithError: error)
    }

    completionHandler(evaluation.disposition, evaluation.credential)
}

它将一个元组类型 (disposition: URLSession.AuthChallengeDisposition, credential: URLCredential?, error: AFError?) 定义为 ChallengeEvaluation,以提高这个类型的可读性和可维护性。
用户评论