在本文的第1部分中,我们已经看到了如何将枚举用作表视图的数据源。 如果您碰巧错过了第1部分,请检查一下。 如前所述,在这一部分中,我将展示网络堆栈中enum的另一个高级用例,我们将使用以下功能。
以下是支持基本get,post请求的任何网络堆栈的组件。
让我们看看如何实现上述每个组件。
我们定义了一个相对于所有其他api端点相对的基本url字符串,并将其包装在一个结构中。
struct BaseURL { 静态让url =“ https://example.com:7979/mobile-app/” }
要实现Api端点,我们可以根据需要以两种方式使用枚举。
在api端点只是静态字符串路径的简单情况下,我们可以使用基于字符串的枚举,如下所示。
枚举ApiPath:String { 案例书=“书籍/全部书籍” 案例类别=“书籍/类别” }
但是,当我们需要基于用户输入添加动态路径参数时,这将不起作用。 例如,我们可能想根据用户选择的类别列出书籍,并且api端点如下所示。
case booksForCategory =“书籍/类别/ 5”
由于此类别ID将随用户选择而变化,因此我们可以包含一个具有用户所选类别ID的变量,然后使用字符串插值将其添加到api路径。
case booksForCategory =“书籍/类别/ \(类别)”
为了使上面的语句真正起作用,我们需要将类别变量注入枚举实例。 因此,我们将在swift enum🙌中使用关联的值。 但是有一个陷阱,如果尝试将关联值添加到枚举,则编译器会抱怨说不允许其同时具有关联值和字符串原始值。 因此,正如我在第1部分中解释的那样,我们将使该枚举符合CustomStringConvertible协议。 现在我们也可以拥有关联的值! 代码如下。
枚举ApiPath:CustomStringConvertible { 案例书 案例类别 案例书ForCategory(字符串)
//符合CustomStringConvertible协议
var description:String { 切换自我{ 案例书: 返回“ books / allBooks” 案例.categories: 返回“书籍/类别” 案例.booksForCategory(让categoryId): 返回“ books / categories / \(categoryId)” } } }
同样,我们将使用基于字符串的枚举,其中包含常用的HTTP方法类型。
枚举RequestType:String { case get =“ GET” 案例发布=“ POST” 大小写=“ PUT” case delete =“删除” }
对于网络错误,我们将使用与ApiPath相同的方法。 实现如下所示。
枚举NetworkingError:CustomStringConvertible {
大小写自定义(消息:字符串) 案例号InternetConnection 案例通用 案例failedWithStatusCode(statusCode:Int)
var description:字符串{
切换自我{
case .noInternetConnection:
返回“请检查您的Internet连接。”
案例.custom(让消息发送):
返回讯息
大小写
返回“存在技术问题。如果问题仍然存在,请与我们联系。”
案例.failedWithStatusCode(让代码):
返回“失败,状态码为\(code)”
}
假设我们有一个对象(Api控制器),该对象处理特定的api请求并向我们返回响应。 让我们将此响应称为ServiceResponse。 如果我们从高层次看,ServiceResponse对于每个API都应该有两个可能的结果。 他们是,
成功后,我们需要响应数据,该数据是JSON数据或强类型的Model对象(例如:本例中的book对象)。 出现故障时,我们需要一条可以显示给用户的消息。
再次,我们可以使用一个枚举来工作……这一次,我们将在枚举中使用泛型。 该代码在下面的代码段中给出。
列举ServiceResponse { 成功案例(T) 案例失败(NetworkingError) }
我们成功使用泛型的原因是因为,这使我们能够在任何Api中使用此ServiceResponse并根据需要成功传递任何类型或对象。
如果失败,我们传递的关联值为NetworkingError,它也是一个枚举。
现在,我们需要将所有部分放在一起,这使我们进入了RequestManager类。 此类充当整个应用程序中所有网络请求的网关。 事不宜迟,让我们继续实施它。
RequestManager类{
//单例实现 静态让共享= RequestManager() 私人init(){}
func request(_ type:RequestType,apiPath:ApiPath,queryParameters:String?= nil,完成:@转义(ServiceResponse )->()){
保护Reachability.isConnectedToNetwork()其他{ 完成(.failure(.noInternetConnection)) 返回 }
让urlString = BaseURL.url + apiPath.description +(queryParameters ??“”) 让url:URL = URL(string:urlString)! 让会话= URLSession.shared
var request = URLRequest(url:url) request.httpMethod = type.rawValue
session.dataTask(with:request){(data,response,error)in //检查所有条件并相应返回 ........ //成功 完成(.success(json))
//失败时 完成(.failure(.generic))
在上面的代码中,我们已将ServiceResponse的通用类型指定为JSON **,例如ServiceResponse 。 由于这是所有不同的Api控制器都将使用的通用方法,因此我们只需返回json响应,然后让api控制器根据需要将json映射到合适的Model类型。
**这是代表SwiftyJSON中的JSON对象的类型,它是最流行的json解析库之一。
最后,让我们实现一个示例Api控制器,在这种情况下,是一个BooksApiController,它会向我们返回给定类别的所有书籍的列表。
为此,我们首先需要定义我们的书本模型,与下面的代码相似。
结构书{ 变量名称:字符串 var id:String var author:String var价格:双倍 var category:String }
现在我们已经准备好Book模型,让我们回到实现BooksApiController的角度。
类BooksApiController { 有趣的getBooksForCategory(_类别:字符串,_完成:@转义(ServiceResponse )->()){ RequestManager.shared.request(.get,apiPath:.booksForCategory(category)){(响应)在
切换响应{ 案例.success(let json): var books = [Book]()
json.arrayValue中的bookRaw { do {//将原始json映射到模型 let book:Book =试试JSONDecoder.decode(json:bookRaw) books.append(book) } { 打印(error.localizedDescription) } }
完成(。成功(书本)) //返回模型数组,在这种情况下为Book
案例。失败(让错误):
完成(.failure(错误)) //只传递错误,以便可以将其显示给用户。 } } }
在上面的代码片段中,这次我们将通用参数类型传递为[Book],因为我们需要从此Api返回一个Book对象数组。 可以根据需要将其更改为任何其他类型。 上面的大多数代码是不言自明的,除了JSONDecoder只是一种对象映射器。 那可能是另一篇文章的主题。 那就是所有的人! 编码愉快!!
如果您喜欢阅读本文,请拍掌a,我很想听听您的反馈意见。