ios开发重用导致全选_开发可重用的网络课程

ios开发重用导致全选

更多开发,更少样板,更容易重构 (More Development, Less Boilerplate, Easier Refactoring)

Image for post
Writing reusable code is like being in multiple places at the same time. Get more done with less!
编写可重用的代码就像同时在多个地方。 事半功倍!

I personally know more than a few Swift Developers who find writing networking code boring. “There’s too much boilerplate code,” they say. The good news is there’s something you can do about it.

我个人认识的很多Swift开发人员都觉得编写网络代码很无聊。 他们说:“样板代码太多。” 好消息是您可以为此做些事情。

With a little creativity, you can write a class that you can use to perform networking tasks across your app. In fact, that should read apps because you can use this in any app that needs URLSession and it can even nearly automatically handle JSON Encoding and Decoding using Codable (in part 2).

稍有创造力,您就可以编写一个类,用于在整个应用程序中执行联网任务。 事实上,这应该阅读应用程序因为你可以在需要URLSession任何应用程序中使用这一点,它甚至可以几乎自动处理JSON编码和解码使用可编码( 部分2 )。

Image for post

First, let’s write a pretty standard network call using URLSession.shared.dataTask. Since we’re already here, why don’t we download Medium’s front page like so?

开始步骤,让我们写使用URLSession.shared.dataTask一个非常标准的网络呼叫。 既然我们已经在这里,为什么不像这样下载Medium的首页呢?

  1. Create a URL

    创建一个URL
  2. Create a request using the URL

    使用URL创建请求
  3. Stub out URLSession.shared.dataTask(with: URLRequest, completionHandler: (Data?, URLResponse?, Error?) -> Void)

    存根URLSession.shared.dataTask(with:URLRequest,completeHandler:(Data ?, URLResponse ?, Error?)-> Void)
  4. Check for errors

    检查错误
  5. Downcast the URLResponse to a HTTPURLResponse

    将URLResponse转换为HTTPURLResponse
  6. Check the status code

    检查状态码
  7. Unwrap the data

    解开数据
  8. Do something with the data

    处理数据

If we somehow had access to the dataTask method that just returns optionals, we could probably put a pretty big ding in the amount of code we’re writing each time. At the same time, we don’t want to completely overwrite the dataTask method in case we want to do some custom error handling. We also probably want to be able to do something other than print the data as an encoded String.

如果我们能够以某种方式访问​​仅返回可选参数的dataTask方法,那么我们可能会在每次编写的代码量中花很多钱。 同时,如果要执行一些自定义错误处理,我们不想完全覆盖dataTask方法。 除了将数据打印为编码的String之外,我们可能还希望能够做其他事情。

我们如何才能两全其美? (How can we have the best of both worlds?)

Look, no error handling! (Actually it’s happening “behind the scenes”)
看,没有错误处理! (实际上,这是在“幕后”发生的)

“Ohh, I see Kenny — so if I don’t handle errors, I write less code? Great strategy…”

“哦,我看到Kenny了-所以如果我不处理错误,我会写更少的代码吗? 好的策略……”

Actually, the beauty of this is I’ve implemented default error handling and response checking “behind the scenes”. If you want to, you can still implement custom error handling and response checking by naming those variables in the parameter list (the part with `data, _, _` ) at any call site .

实际上,这样做的好处是我已经在“幕后”实现了默认的错误处理和响应检查。 如果愿意,您仍然可以通过在任何调用站点的参数列表(带有`data,_,_`的部分)中命名这些变量来实现自定义错误处理和响应检查。

Image for post

架构 (The Architecture)

Image for post

While we’re on the topic of reusable code, let’s use a protocol in part of our implementation. This protocol isn’t necessary here, as you can both extend URLSession, and use this networking class we’re about to create without it. BUT — you can couple this protocol with a Mock Data Loader class and use that very powerful feature in Unit Testing (and testing in general when you want a quick result).

当我们讨论可重用代码的主题时,让我们在实现的一部分中使用协议。 这里不需要该协议,因为您既可以扩展URLSession,也可以使用我们将在没有该类的情况下创建的网络类。 但是- 您可以将此协议与Mock Data Loader类结合使用,并在单元测试中使用该功能非常强大的功能(通常在需要快速结果时进行测试)。

协议书 (The Protocol)

That’s it. Lightweight at its best. But pound for pound, it’s a fighter for sure
而已。 轻巧至极。 但是一磅又一磅,这肯定是个战士

让我们提供默认实现 (Let’s Provide Default Implementation)

extension URLSession: NetworkLoader {
func loadData(using request: URLRequest, with completion: @escaping (Data?, URLResponse?, Error?) -> Void) {
self.dataTask(with: request, completionHandler: completion).resume()
}
}

We could do that and call it a day, but that would more or less leave us with what we already have. Except if you’ll notice (and maybe if you noticed in the implementation above) one thing is always taken care of — you never have to remember .resume() again.

我们可以做到这一点,将其称为“一天”,但这或多或少会给我们留下我们已经拥有的东西。 除非您会注意到(也许您在上面的实现中注意到),否则总是会注意一件事- 您不必再记住.resume()了

What we’re doing here is leveraging the dataTask and providing default implementation for a common use case. But if you need .resume() and the rest of the power of the dataTask, that method is still there, untouched.

我们在这里所做的是利用dataTask并为常见用例提供默认实现。 但是,如果您需要.resume()和dataTask的其余功能,则该方法仍然存在,并没有涉及。

默认实施,更进一步 (Default Implementation, One Step Further)

There’s our default error and response handling that we’re probably pretty familiar with!
我们可能非常熟悉我们的默认错误和响应处理!

So, what did we just do?

那么,我们只是做什么?

  1. We implemented a protocol that requires anything conforming to it to have a method that takes the same parameters as a dataTask, but with a HTTPURLResponse instead of a plain URLResponse

    我们实现了一个协议,该协议要求所有与之兼容的协议具有与dataTask相同的参数,但使用HTTPURLResponse而不是普通的URLResponse
  2. We extended URLSession with that protocol and provided default implementation

    我们使用该协议扩展了URLSession并提供了默认实现
  3. In our default implementation, we’re handling errors, downcasting the response to a HTTPURLResponse, and completing all 3 parameters regardless of them being nil or containing a value.

    在我们的默认实现中,我们正在处理错误,将响应向下转换为HTTPURLResponse,并完成所有3个参数,无论它们为nil还是包含值。

You can now use this method with any network call, and that default error/response handling is taken care of. You just need to do something with the data.

现在,您可以在任何网络调用中使用此方法,并且可以处理默认的错误/响应处理。 您只需要对数据做些事情。

BUT if you want different implementation (maybe an alert if there’s an error) you can just provide the error variable in your loadData’s completion handler and handle it how you see fit. Or maybe you want to check a status code other than 200. Just name the response variable and handle it.

但是,如果您想要不同的实现(如果有错误,可能会发出警报),您只需在loadData的完成处理程序中提供error变量,然后按照您认为合适的方式进行处理即可。 或者,也许您想检查200以外的状态码。只需命名响应变量并进行处理即可。

Again, the beauty of this is you maintain full control without having to refactor and boilerplate implementation is taken care of.

再次,这样做的好处是您可以保持完全控制,而无需重构, 并且样板实现也得到了照顾。

Image for post

但是,等等,还有更多! (But Wait, There’s More!)

Let’s handle some more boilerplate code, and prevent ourselves from errors caused by “magic strings”. Magic strings are strings that essentially control the flow of your application, such as “Content-Type” and “application/json” or “GET, PUT, UPDATE ….”. If you get these wrong, your call could potentially fail, disrupting the flow of your application.

让我们处理更多样板代码, 防止自己因“魔力弦”引起的错误。 魔术字符串是实质上控制应用程序流的字符串,例如“ Content-Type”和“ application / json”或“ GET,PUT,UPDATE…”。 如果您弄错了这些,您的呼叫可能会失败,从而中断您的应用程序流程。

枚举是你的朋友 (Enums Are Your Friend)

Enums help us encapsulate data, properties, and methods that are specific to a certain task... with some special rules that I could probably write several articles on if I knew enough about them. I mainly use enums for encapsulation/convenience.

枚举可帮助我们封装特定于某项任务的数据,属性和方法……具有一些特殊的规则,如果我对这些规则了解不多,我可能会写几篇文章。 我主要使用enum进行封装/方便。

When we declare an enum with a rawValue type of String, we get the case name as a string “for free” or we can provide an assigned rawValue (String). This is very convenient for a number of reasons. In our case today, they’re going to help us not make typos, restrict our choices of HTTPMethods with only valid ones, and make it easier to refactor our code later.

当我们声明一个rawValue类型为String的枚举时,我们将案例名称作为字符串“免费”获得,或者我们可以提供一个已分配的rawValue(String)。 由于许多原因,这非常方便。 在今天的情况下,它们将帮助我们避免输入错误,仅对有效的HTTPMethods进行选择,并在以后重构代码时变得更加容易。

So far, you should have something that looks like this (it’s ok if you prefer to have separate files):

到目前为止,您应该具有类似以下的内容(如果您希望有单独的文件也可以):

班上 (The Class)

Let’s make a class with a dataLoader: NetworkLoader property and an enum called HTTPMethod. If your only intention is to use this call for live networking, the dataLoader property isn’t necessary (just use URLSession.shared) — or you can still use it and set it to URLSession.shared and skip the initializer. This setup is perfect if you intend on being able to inject a mock dataTask for testing

让我们用dataLoader:NetworkLoader属性和一个名为HTTPMethod的枚举创建一个类。 如果您唯一的目的是使用此调用进行实时联网,则不需要dataLoader属性(只需使用URLSession.shared),或者您仍然可以使用它并将其设置为URLSession.shared并跳过初始化程序。 如果您打算注入模拟数据以进行测试,则此设置非常理想

I’m going to call my class NetworkService.

我要调用我的类NetworkService。

Let’s implement one more method that we’ll use to create requests, and Part 1 of our NetworkService will be complete, ready to create a request with one of several HTTP Methods and send it off to distant lands. I’m a fan of semantics, so let’s call this method createRequest.

让我们再实现一个用于创建请求的方法,我们的NetworkService第1部分将完成,可以使用几种HTTP方法之一创建请求并将其发送到遥远的土地。 我是语义迷,所以我们将此方法称为createRequest。

And here’s how we use that to create a GET request to https://medium.com. If you want a different type of request, just change the method parameter using dot syntax (.put, .post, etc…)

这就是我们使用它来创建对https://medium.com的GET请求的方法 如果您需要其他类型的请求,只需使用点语法(.put,.post等)更改method参数即可。

And as at the beginning of the article in the 2nd example, putting it all together to download Medium.com’s homepage, we can simply do this:

就像在第二个示例中的文章开头一样,将所有内容放在一起以下载Medium.com的主页,我们可以简单地做到这一点:

Look, no error handling in our implementation at the call site!
看,我们在呼叫站点的实现中没有错误处理!
Image for post

结语 (Wrap-Up)

Ok, so we wrote a protocol, an extension, and a class for a few methods that leverage existing classes and methods, but make it more convenient for us to do our jobs. Hopefully you can see how powerful this is and make it completely your own.

好的,所以我们为一些利用现有类和方法的方法编写了协议,扩展和类,但是这使我们更方便地完成工作。 希望您能看到它的强大功能,并完全由您自己制作。

By writing reusable code, we can more quickly develop features requiring the same code rather than copying and pasting. If you want to refactor later, you would only have to refactor one method, and all of the places you’ve implemented that method would update with the new logic.

通过编写可重用的代码,我们可以更快地开发需要相同代码的功能,而不是复制和粘贴。 如果要稍后进行重构,则只需重构一种方法,并且实现该方法的所有位置都将使用新逻辑进行更新。

而已! 第1部分完成! (That’s It! Part 1 is Complete!)

Please join me for part 2, where we’ll implement a Codable struct, use it to send encoded JSON to firebase, then in part 3, we’ll use the same struct to download and decode that JSON and display it in a UITableView.

请加入我的第二部分 ,我们将实现一个Codable结构,将其用于将编码的JSON发送到firebase,然后在第三部分中,我们将使用相同的结构来下载和解码该JSON并将其显示在UITableView中。

We’ll implement it all using modular code that you can use over and over again to easily perform your most common networking tasks. Hopefully if you don’t see the value in writing reusable code now, you will by the end of part 2!

我们将使用模块化代码来实现所有这些功能,您可以一遍又一遍地使用它们,以轻松执行最常见的联网任务。 希望如果您现在看不到编写可重用代码的价值,那么您将在第2部分结尾!

这是第2部分: (Here’s Part 2:)

第三部分: (And Part 3:)

翻译自: https://medium.com/swlh/developing-a-reusable-networking-class-66ef1f7566f

ios开发重用导致全选

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值