# 21.Swift轻量级网络封装：SwiftyServiceProtocol（适用于混编或纯Swift项目）

## 一、前言

随着Swift越来越成熟，越来越多的项目也开始使用Swift了。很多朋友应该都有遇到和OC混编的情况。

我自己的话，纯Swift和混编的都做过。在爽过纯Swift后，在混编时经常会有被困住手脚的感觉。

尤其这两年的公司项目，很多老代码和必须依赖的基础库都是OC。特别是网络库（基于AFN），又不能不用公司的。

但是在使用过Swift的[Moya](https://github.com/Moya/Moya)框架后，对于在混编的Swift中不能写出很Swift的网络请求这件事尤为难受。

于是有了想解决这点痛苦的想法。就有了 `SwiftyServiceProtocol`

> 对`Swift` 的 `协议` `枚举` `泛型`等有一定了解的话会很便于理解

## 二、封装目标

1. 不依赖任何三方网络库
2. 便于更换底层网络库（AFN? Alamofire? 自研网络库？ 无痛切换。极端一点你甚至可以不同模块使用不同网络库)
3. 用起来很Moya很Swifty
4. 兼容多模块多域名
5. 轻量
6. 用于纯Swift项目或者混编项目（不考虑OC调用。原因：单纯的不喜欢）
7. 便于模块化处理

## 三、SwiftyServiceProtocol

源码在此：[GitHub*SwiftyServiceProtocol*喜欢的话点个小星星吧⭐️](https://github.com/RyukieSama/Swifty/blob/master/Swifty/Protocol/Service/Service.swift)

这个协议十分轻量，不算注释也就12行代码。

### 3.1 在项目中对 SwiftyServiceProtocol 进行拓展

```swift
public protocol MyServiceProtocol: SwiftyServiceProtocol where SwiftyServiceCallBackType == 你的网络库的回调 {

}

extension MyServiceProtocol {
    /// 如果你的项目只有一个域名，在这里写死就好。如果不同模块有不同的域名，那么在对应的Service中实现这个get就行，测试环境生产环境的逻辑也可以放在这里
    var base: String {
        return "你的域名"
    }

    var urlString: String {
        return base + "/" + path
    }

    func request(completion: SwiftyServiceCallBackType?) {
        switch method {
        case .GET:
            get(completion: completion)
        case .POST:
            post(completion: completion)
        }
    }

    // MARK: - Private
    private func post(completion: 你的网络库的回调?) {
        // 你的POST实现
    }

    private func get(completion: 你的网络库的回调?) {
        // 你的GET实现
    }
}
```

### 3.2 实际使用

> 这里以用户模块的一些请求为例

#### 定义相关Service

```swift
enum YourUserService { // 定义你需要的接口
    /// 获取用户信息
    case Info(uid: Int64)
    /// 关注某人
    case Follow(uid: Int64)
    /// 取消关注某人
    case UnFollow(uid: Int64)
}

extension YourUserService: MyServiceProtocol {
    // var base: String {
    //     return "如果这个模块有不同模块有不同的域名，在这里实现这个get就行"
    // }

    /// 接口参数
    var parameters: [AnyHashable : Any]? {
        switch self {
        case let .Info(uid):
            return ["uid" : uid]
        case .Follow(let uid):
            return ["id" : uid]
        case .UnFollow(let uid):
            return ["id" : uid]
        }
    }

    /// 接口路径
    var path: String {
        switch self {
        case .Info:
            return "info的path"
        case .Follow:
            return "follow的path"
        case .UnFollow:
            return "unfollow的path"
        }
    }

    /// 请求方法选择
    var method: SwiftyServiceMethod {
        switch self {
        case .Info:
            return .GET
        default:
            return .POST
        }
    }
}
```

### 调用场景

```swift
UserService
    .Info(yourUser.uid)
    .request { (response) in
        // 处理网络回调
    }
```

## 四、总结

这个协议我自己已经在两个混编项目中使用了，如果你也喜欢的话，欢迎来点个小星星⭐️[GitHub\_SwiftyServiceProtocol](https://github.com/RyukieSama/Swifty/blob/master/Swifty/Protocol/Service/Service.swift)

参考： [Moya](https://github.com/Moya/Moya)


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://ryukiedev.gitbook.io/wiki/swift/swift-qing-liang-ji-wang-luo-feng-zhuang-swiftyserviceprotocol-shi-yong-yu-hun-bian-huo-chun-swift-x.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
