.key, value: String(describing:

Kaip izoliuoti kliento ir serverio sąveikos logiką „iOS“ programose

Šiais laikais dauguma mobiliųjų programų labai priklauso nuo kliento ir serverio sąveikos. Tai ne tik reiškia, kad jie gali didžiąją dalį savo sunkių užduočių iškrauti į vidinius serverius, bet ir leidžia šioms mobiliosioms programoms pasiūlyti įvairiausių funkcijų ir funkcijų, kurias galima padaryti tik internetu.

Užpakaliniai serveriai paprastai yra skirti pasiūlyti savo paslaugas per RESTful API . Paprastesnėms programoms dažnai kyla pagunda gauti sukūrus spagečių kodą; maišymo kodas, kuris iškviečia API su likusia programos logika. Tačiau kai programos tampa vis sudėtingesnės ir susiduria su vis daugiau API, gali būti nemalonu sąveikauti su šiomis API nestruktūrizuotai, neplanuotai.



Laikykite „iOS“ programos kodą netvarką naudodami gerai sukurtą „REST“ kliento tinklo modulį.



Laikykite „iOS“ programos kodą netvarką naudodami gerai sukurtą „REST“ kliento tinklo modulį. Čivināšana

Šiame straipsnyje aptariamas architektūrinis požiūris, kaip sukurti švarų „REST“ kliento tinklo modulį „iOS“ programos tai leidžia išlaikyti visą kliento ir serverio sąveikos logiką izoliuotą nuo likusio programos kodo.

Kliento-serverio programos

Tipiška kliento ir serverio sąveika atrodo maždaug taip:



  1. Vartotojas atlieka tam tikrą veiksmą (pvz., Bakstelėdamas kurį nors mygtuką arba atlikdamas kitą gestą ekrane).
  2. Programa parengia ir siunčia HTTP / REST užklausą atsakydama į vartotojo veiksmą.
  3. Serveris apdoroja užklausą ir atitinkamai atsako į programą.
  4. Programa gauna atsakymą ir pagal tai atnaujina vartotojo sąsają.

Iš pirmo žvilgsnio visas procesas gali atrodyti paprastas, tačiau mes turime galvoti apie detales.

Net darant prielaidą, kad užpakalinio serverio API veikia taip, kaip reklamuojama (tai yra ne visada būna!), jis dažnai gali būti netinkamai suprojektuotas, todėl jį naudoti yra neefektyvu ar net sunku. Vienas dažnas susierzinimas yra tas, kad visi skambučiai į API reikalauja, kad skambinantysis perdėtai pateiktų tą pačią informaciją (pvz., Kaip formuojami užklausos duomenys, prieigos raktas, kurį serveris gali naudoti šiuo metu prisijungusiam vartotojui identifikuoti ir pan.).

Mobiliosioms programoms taip pat gali tekti vienu metu naudoti kelis vidinius serverius skirtingiems tikslams. Pavyzdžiui, vienas serveris gali būti skirtas vartotojo autentifikavimui, o kitas - tik analizės duomenų rinkimui.



Be to, įprastas REST klientas turės padaryti ne tik nuotolines API. Galimybė atšaukti laukiančias užklausas arba švarus ir valdomas požiūris į klaidų tvarkymą yra funkcionalumo, kurį reikia įdiegti bet kurioje patikimoje mobiliojoje programoje, pavyzdžiai.

Architektūros apžvalga

Mūsų REST kliento pagrindas bus pagrįstas šiais komponentais:

Taip sąveikaus kiekvienas iš šių komponentų:

Rodyklės nuo 1 iki 10 aukščiau esančiame paveikslėlyje rodo idealią operacijų seką tarp programos, iškviečiančios paslaugą, ir paslaugos, galiausiai pateikiančios prašomus duomenis kaip modelio objektą. Kiekvienas to srauto komponentas turi tam tikrą vaidmenį užtikrinant rūpesčių atskyrimas modulio viduje.

Įgyvendinimas

„REST“ klientą įgyvendinsime kaip įsivaizduojamo socialinio tinklo programos dalį, į kurią įkelsime šiuo metu prisijungusių vartotojų draugų sąrašą. Darysime prielaidą, kad mūsų nuotolinis serveris atsakymams naudoja JSON.

Pradėkime nuo savo modelių ir analizatorių diegimo.

Nuo neapdoroto JSON iki pavyzdinių objektų

Pirmasis mūsų modelis User apibrėžia bet kurio socialinio tinklo vartotojo informacijos struktūrą. Kad viskas būtų paprasta, įtrauksime tik laukus, kurie yra būtini šiai pamokai (tikroje programoje struktūra paprastai turėtų daug daugiau savybių).

struct User { var id: String var email: String? var name: String? }

Kadangi visus naudotojo duomenis gausime iš užpakalinio serverio per jo API, mums reikia būdo išanalizuoti API atsakymą į galiojančią User objektas. Norėdami tai padaryti, prie User pridėsime konstruktorių kuris priima išanalizuotą JSON objektą (Dictionary) kaip parametrą. Mes apibrėžsime savo JSON objektą kaip slapyvardį:

typealias JSON = [String: Any]

Tada prie savo User pridėsime konstruktoriaus funkciją struktūra taip:

extension User { init?(json: JSON) { guard let id = json['id'] as? String else { return nil } self.id = id self.email = json['email'] as? String self.name = json['name'] as? String } }

Kad išsaugotume pradinį numatytąjį User konstruktorių, konstruktorių pridedame per plėtinį User tipo.

Tada sukurkite User objektas iš neapdoroto API atsakymo, turime atlikti šiuos du veiksmus:

// Transform raw JSON data to parsed JSON object using JSONSerializer (part of standard library) let userObject = (try? JSONSerialization.jsonObject(with: data, options: [])) as? JSON // Create an instance of `User` structure from parsed JSON object let user = userObject.flatMap(User.init)

Supaprastintas klaidų tvarkymas

Apibrėžime tipą, kuris atspindi įvairias klaidas, kurios gali atsirasti bandant sąveikauti su vidiniais serveriais. Visas tokias klaidas galime suskirstyti į tris pagrindines kategorijas:

Savo klaidos objektus galime apibrėžti kaip surašymo tipą. Ir kol mes tai pasieksime, gera idėja yra sukurti savo ServiceError tipas atitinka Error protokolas . Tai leis mums naudoti ir valdyti šias klaidų reikšmes naudojant standartinius „Swift“ pateiktus mechanizmus (pvz., Naudojant klaidą išmetant throw).

enum ServiceError: Error { case noInternetConnection case custom(String) case other }

Skirtingai nuo noInternetConnection ir other klaidų, pasirinktinė klaida turi su ja susietą vertę. Tai leis mums naudoti serverio atsakymą į klaidą kaip susietą pačios klaidos vertę, taip suteikiant klaidai daugiau konteksto.

Dabar pridėkime errorDescription nuosavybės į ServiceError surašymas, kad klaidos būtų aprašomesnės. Pridėsime koduotus pranešimus, skirtus noInternetConnection ir other klaidų ir naudokite susietą vertę kaip custom pranešimą klaidos.

extension ServiceError: LocalizedError { var errorDescription: String? { switch self { case .noInternetConnection: return 'No Internet connection' case .other: return 'Something went wrong' case .custom(let message): return message } } }

Yra tik dar vienas dalykas, kurį turime įgyvendinti savo ServiceError surašymas. Jei tai custom klaidą, turime transformuoti serverio JSON duomenis į klaidos objektą. Norėdami tai padaryti, mes naudojame tą patį metodą, kurį naudojome modelių atveju:

extension ServiceError { init(json: JSON) { if let message = json['message'] as? String { self = .custom(message) } else { self = .other } } }

Atotrūkio tarp programos ir vidinio serverio panaikinimas

Kliento komponentas bus tarpininkas tarp programos ir vidinio serverio. Tai yra kritinis komponentas, apibrėžiantis, kaip programa ir serveris susisieks, tačiau nieko nežinos apie duomenų modelius ir jų struktūras. Klientas bus atsakingas už tam tikrų URL su pateiktais parametrais iškvietimą ir gaunamų JSON duomenų, analizuotų kaip JSON objektų, grąžinimą.

enum RequestMethod: String { case get = 'GET' case post = 'POST' case put = 'PUT' case delete = 'DELETE' } final class WebClient { private var baseUrl: String init(baseUrl: String) { self.baseUrl = baseUrl } func load(path: String, method: RequestMethod, params: JSON, completion: @escaping (Any?, ServiceError?) -> ()) -> URLSessionDataTask? { // TODO: Add implementation } }

Panagrinėkime, kas vyksta aukščiau pateiktame kode ...

Pirma, mes paskelbėme surašymo tipą RequestMethod, kuris apibūdina keturis įprastus HTTP metodus. Tai yra vienas iš metodų, naudojamų REST API.

WebClient klasėje yra baseURL ypatybė, kuri bus naudojama sprendžiant visus gautus santykinius URL. Jei mūsų programai reikia sąveikauti su keliais serveriais, galime sukurti kelis WebClient egzempliorius kiekvienas turi skirtingą baseURL reikšmę.

Klientas turi vieną metodą load, kuris eina keliu, palyginti su baseURL kaip parametrą, užklausos metodą, užklausos parametrus ir užbaigimo uždarymą. Užbaigimo uždarymas iškviečiamas su išanalizuotu JSON ir ServiceError kaip parametrus. Kol kas aukščiau pateiktas metodas nėra įgyvendintas, prie kurio greitai prisijungsime.

Prieš įgyvendinant load metodas, mums reikia būdo sukurti URL nuo visos turimos informacijos iki metodo. Išplėsime URL klasė šiam tikslui:

extension URL { init(baseUrl: String, path: String, params: JSON, method: RequestMethod) { var components = URLComponents(string: baseUrl)! components.path += path switch method { case .get, .delete: components.queryItems = params.map { URLQueryItem(name: $0.key, value: String(describing: $0.value)) } default: break } self = components.url! } }

Čia paprasčiausiai pridedame kelią prie pagrindinio URL. GET ir DELETE HTTP metodams užklausos parametrus taip pat pridedame prie URL eilutės.

Tada turime sugebėti sukurti URLRequest egzempliorius iš pateiktų parametrų. Norėdami tai padaryti, padarysime kažką panašaus į tai, ką padarėme URL

extension URLRequest { init(baseUrl: String, path: String, method: RequestMethod, params: JSON) { let url = URL(baseUrl: baseUrl, path: path, params: params, method: method) self.init(url: url) httpMethod = method.rawValue setValue('application/json', forHTTPHeaderField: 'Accept') setValue('application/json', forHTTPHeaderField: 'Content-Type') switch method { case .post, .put: httpBody = try! JSONSerialization.data(withJSONObject: params, options: []) default: break } } }

Čia pirmiausia sukuriame URL naudojant konstruktorių iš pratęsimo. Tada inicijuojame URLRequest egzempliorių naudodami šį URL, prireikus nustatykite kelias HTTP antraštes, o tada, jei POST arba PUT HTTP metodai, pridėkite parametrus prie užklausos teksto.

Įvykdę visas būtinas sąlygas, galime įgyvendinti load metodas:

final class WebClient { private var baseUrl: String init(baseUrl: String) { self.baseUrl = baseUrl } func load(path: String, method: RequestMethod, params: JSON, completion: @escaping (Any?, ServiceError?) -> ()) -> URLSessionDataTask? { // Checking internet connection availability if !Reachability.isConnectedToNetwork() { completion(nil, ServiceError.noInternetConnection) return nil } // Adding common parameters var parameters = params if let token = KeychainWrapper.itemForKey('application_token') { parameters['token'] = token } // Creating the URLRequest object let request = URLRequest(baseUrl: baseUrl, path: path, method: method, params: params) // Sending request to the server. let task = URLSession.shared.dataTask(with: request) { data, response, error in // Parsing incoming data var object: Any? = nil if let data = data { object = try? JSONSerialization.jsonObject(with: data, options: []) } if let httpResponse = response as? HTTPURLResponse, (200..<300) ~= httpResponse.statusCode { completion(object, nil) } else { let error = (object as? JSON).flatMap(ServiceError.init) ?? ServiceError.other completion(nil, error) } } task.resume() return task } }

load aukščiau pateiktas metodas atlieka šiuos veiksmus:

  1. Patikrinkite, ar yra interneto ryšys. Jei nėra interneto ryšio, mes nedelsdami paskambiname į užbaigimo procesą paspausdami noInternetConnection klaida kaip parametras. (Pastaba: Reachability kode yra pasirinktinė klasė, kuri naudoja vienas iš bendrų požiūrių patikrinti interneto ryšį.)
  2. Pridėkite bendrų parametrų. . Tai gali apimti įprastus parametrus, pvz., Programos prieigos raktą ar vartotojo ID.
  3. Sukurkite URLRequest objektas, naudojant konstruktorių iš pratęsimo.
  4. Siųskite užklausą į serverį. Mes naudojame URLSession objektas siųsti duomenis į serverį.
  5. Analizuokite gaunamus duomenis. Kai serveris atsako, pirmiausia išanalizuojame atsakymo naudingąją apkrovą į JSON objektą naudodami JSONSerialization Tada mes patikriname atsakymo būsenos kodą. Jei tai yra sėkmės kodas (t. Y. Intervale nuo 200 iki 299), mes vadiname užbaigimo uždarymą naudojant JSON objektą. Kitu atveju JSON objektą paverčiame ServiceError objektą ir iškvieskite užbaigimo uždarymą su tuo klaidos objektu.

Logiškai susietų operacijų paslaugų apibrėžimas

Mūsų programos atveju mums reikia paslaugos, kuri spręstų užduotis, susijusias su vartotojo draugais. Tam sukuriame FriendsService klasė. Idealiu atveju tokia klasė bus atsakinga už tokias operacijas kaip draugų sąrašo gavimas, naujo draugo pridėjimas, draugo pašalinimas, draugų sugrupavimas į kategoriją ir kt. Siekdami paprastumo šioje pamokoje, įgyvendinsime tik vieną metodą :

final class FriendsService { private let client = WebClient(baseUrl: 'https://your_server_host/api/v1') @discardableResult func loadFriends(forUser user: User, completion: @escaping ([User]?, ServiceError?) -> ()) -> URLSessionDataTask? { let params: JSON = ['user_id': user.id] return client.load(path: '/friends', method: .get, params: params) { result, error in let dictionaries = result as? [JSON] completion(dictionaries?.flatMap(User.init), error) } } }

FriendsService klasėje yra client tipo nuosavybė WebClient. Jis inicijuojamas su pagrindiniu nuotolinio serverio, kuris yra atsakingas už draugų valdymą, URL. Kaip minėta anksčiau, kitose paslaugų klasėse galime turėti kitokį WebClient egzempliorių jei reikia, inicializuojamas kitu URL.

Jei programa veikia tik su vienu serveriu, WebClient klasei gali būti suteiktas konstruktorius, kuris inicijuoja to serverio URL:

final class WebClient { // ... init() { self.baseUrl = 'https://your_server_base_url' } // ... }

loadFriends metodas, kai jis naudojamas, paruošia visus reikiamus parametrus ir naudoja FriendService nurodytą WebClient pateikti API užklausą. Gavęs atsakymą iš serverio per WebClient, jis transformuoja JSON objektą į User modelius ir vadina užbaigimo uždarymą su jais kaip parametrą.

Tipiškas FriendService naudojimas gali atrodyti taip:

let friendsTask: URLSessionDataTask! let activityIndicator: UIActivityIndicatorView! var friends: [User] = [] func friendsButtonTapped() { friendsTask?.cancel() //Cancel previous loading task. activityIndicator.startAnimating() //Show loading indicator friendsTask = FriendsService().loadFriends(forUser: currentUser) {[weak self] friends, error in DispatchQueue.main.async { self?.activityIndicator.stopAnimating() //Stop loading indicators if let error = error { print(error.localizedDescription) //Handle service error } else if let friends = friends { self?.friends = friends //Update friends property self?.updateUI() //Update user interface } } } }

Ankstesniame pavyzdyje mes darome prielaidą, kad funkcija friendsButtonTapped yra iškviečiamas kiekvieną kartą, kai vartotojas paliečia mygtuką, skirtą parodyti savo draugų sąrašą tinkle. Taip pat saugome nuorodą į užduotį friendsTask nuosavybę, kad galėtume bet kada atšaukti užklausą paskambinę friendsTask?.cancel()

Tai leidžia mums geriau kontroliuoti laukiančių prašymų gyvavimo ciklą, leidžiant juos nutraukti, kai nustatome, kad jie tapo nebesvarbūs.

Išvada

Šiame straipsnyje aš pasidalinau paprasta tinklo modulio, skirto jūsų „iOS“ programai, architektūra, kuri yra nereikšminga įgyvendinti ir gali būti pritaikyta sudėtingiems daugumos „iOS“ programų tinklo poreikiams. Tačiau svarbiausia yra tai, kad tinkamai suprojektuotas REST klientas ir jį lydintys komponentai, izoliuoti nuo likusios jūsų programos logikos, gali padėti išlaikyti jūsų programos kliento ir serverio sąveikos kodą paprastą, net jei pati programa tampa vis sudėtingesnė. .

Tikiuosi, kad šis straipsnis jums bus naudingas kuriant kitą „iOS“ programą. Galite rasti šio tinklo modulio šaltinio kodą „GitHub“ . Patikrinkite kodą, išsišakokite, pakeiskite, žaiskite su juo.

Jei manote, kad kita architektūra yra labiau tinkama jums ir jūsų projektui, pasidalykite išsamia informacija toliau pateiktame komentarų skyriuje.

Susijęs: RESTful API naudojimo ir duomenų patvarumo „iOS“ supaprastinimas naudojant „Mantle“ ir „Realm“ .value)) } default: break } self = components.url! } }

Čia paprasčiausiai pridedame kelią prie pagrindinio URL. GET ir DELETE HTTP metodams užklausos parametrus taip pat pridedame prie URL eilutės.

Tada turime sugebėti sukurti URLRequest egzempliorius iš pateiktų parametrų. Norėdami tai padaryti, padarysime kažką panašaus į tai, ką padarėme URL

extension URLRequest { init(baseUrl: String, path: String, method: RequestMethod, params: JSON) { let url = URL(baseUrl: baseUrl, path: path, params: params, method: method) self.init(url: url) httpMethod = method.rawValue setValue('application/json', forHTTPHeaderField: 'Accept') setValue('application/json', forHTTPHeaderField: 'Content-Type') switch method { case .post, .put: httpBody = try! JSONSerialization.data(withJSONObject: params, options: []) default: break } } }

Čia pirmiausia sukuriame URL naudojant konstruktorių iš pratęsimo. Tada inicijuojame URLRequest egzempliorių naudodami šį URL, prireikus nustatykite kelias HTTP antraštes, o tada, jei POST arba PUT HTTP metodai, pridėkite parametrus prie užklausos teksto.

Įvykdę visas būtinas sąlygas, galime įgyvendinti load metodas:

final class WebClient { private var baseUrl: String init(baseUrl: String) { self.baseUrl = baseUrl } func load(path: String, method: RequestMethod, params: JSON, completion: @escaping (Any?, ServiceError?) -> ()) -> URLSessionDataTask? { // Checking internet connection availability if !Reachability.isConnectedToNetwork() { completion(nil, ServiceError.noInternetConnection) return nil } // Adding common parameters var parameters = params if let token = KeychainWrapper.itemForKey('application_token') { parameters['token'] = token } // Creating the URLRequest object let request = URLRequest(baseUrl: baseUrl, path: path, method: method, params: params) // Sending request to the server. let task = URLSession.shared.dataTask(with: request) { data, response, error in // Parsing incoming data var object: Any? = nil if let data = data { object = try? JSONSerialization.jsonObject(with: data, options: []) } if let httpResponse = response as? HTTPURLResponse, (200..<300) ~= httpResponse.statusCode { completion(object, nil) } else { let error = (object as? JSON).flatMap(ServiceError.init) ?? ServiceError.other completion(nil, error) } } task.resume() return task } }

load aukščiau pateiktas metodas atlieka šiuos veiksmus:

  1. Patikrinkite, ar yra interneto ryšys. Jei nėra interneto ryšio, mes nedelsdami paskambiname į užbaigimo procesą paspausdami noInternetConnection klaida kaip parametras. (Pastaba: Reachability kode yra pasirinktinė klasė, kuri naudoja vienas iš bendrų požiūrių patikrinti interneto ryšį.)
  2. Pridėkite bendrų parametrų. . Tai gali apimti įprastus parametrus, pvz., Programos prieigos raktą ar vartotojo ID.
  3. Sukurkite URLRequest objektas, naudojant konstruktorių iš pratęsimo.
  4. Siųskite užklausą į serverį. Mes naudojame URLSession objektas siųsti duomenis į serverį.
  5. Analizuokite gaunamus duomenis. Kai serveris atsako, pirmiausia išanalizuojame atsakymo naudingąją apkrovą į JSON objektą naudodami JSONSerialization Tada mes patikriname atsakymo būsenos kodą. Jei tai yra sėkmės kodas (t. Y. Intervale nuo 200 iki 299), mes vadiname užbaigimo uždarymą naudojant JSON objektą. Kitu atveju JSON objektą paverčiame ServiceError objektą ir iškvieskite užbaigimo uždarymą su tuo klaidos objektu.

Logiškai susietų operacijų paslaugų apibrėžimas

Mūsų programos atveju mums reikia paslaugos, kuri spręstų užduotis, susijusias su vartotojo draugais. Tam sukuriame FriendsService klasė. Idealiu atveju tokia klasė bus atsakinga už tokias operacijas kaip draugų sąrašo gavimas, naujo draugo pridėjimas, draugo pašalinimas, draugų sugrupavimas į kategoriją ir kt. Siekdami paprastumo šioje pamokoje, įgyvendinsime tik vieną metodą :

final class FriendsService { private let client = WebClient(baseUrl: 'https://your_server_host/api/v1') @discardableResult func loadFriends(forUser user: User, completion: @escaping ([User]?, ServiceError?) -> ()) -> URLSessionDataTask? { let params: JSON = ['user_id': user.id] return client.load(path: '/friends', method: .get, params: params) { result, error in let dictionaries = result as? [JSON] completion(dictionaries?.flatMap(User.init), error) } } }

FriendsService klasėje yra client tipo nuosavybė WebClient. Jis inicijuojamas su pagrindiniu nuotolinio serverio, kuris yra atsakingas už draugų valdymą, URL. Kaip minėta anksčiau, kitose paslaugų klasėse galime turėti kitokį WebClient egzempliorių jei reikia, inicializuojamas kitu URL.

Jei programa veikia tik su vienu serveriu, WebClient klasei gali būti suteiktas konstruktorius, kuris inicijuoja to serverio URL:

final class WebClient { // ... init() { self.baseUrl = 'https://your_server_base_url' } // ... }

loadFriends metodas, kai jis naudojamas, paruošia visus reikiamus parametrus ir naudoja FriendService nurodytą WebClient pateikti API užklausą. Gavęs atsakymą iš serverio per WebClient, jis transformuoja JSON objektą į User modelius ir vadina užbaigimo uždarymą su jais kaip parametrą.

Tipiškas FriendService naudojimas gali atrodyti taip:

let friendsTask: URLSessionDataTask! let activityIndicator: UIActivityIndicatorView! var friends: [User] = [] func friendsButtonTapped() { friendsTask?.cancel() //Cancel previous loading task. activityIndicator.startAnimating() //Show loading indicator friendsTask = FriendsService().loadFriends(forUser: currentUser) {[weak self] friends, error in DispatchQueue.main.async { self?.activityIndicator.stopAnimating() //Stop loading indicators if let error = error { print(error.localizedDescription) //Handle service error } else if let friends = friends { self?.friends = friends //Update friends property self?.updateUI() //Update user interface } } } }

Ankstesniame pavyzdyje mes darome prielaidą, kad funkcija friendsButtonTapped yra iškviečiamas kiekvieną kartą, kai vartotojas paliečia mygtuką, skirtą parodyti savo draugų sąrašą tinkle. Taip pat saugome nuorodą į užduotį friendsTask nuosavybę, kad galėtume bet kada atšaukti užklausą paskambinę friendsTask?.cancel()

Tai leidžia mums geriau kontroliuoti laukiančių prašymų gyvavimo ciklą, leidžiant juos nutraukti, kai nustatome, kad jie tapo nebesvarbūs.

Išvada

Šiame straipsnyje aš pasidalinau paprasta tinklo modulio, skirto jūsų „iOS“ programai, architektūra, kuri yra nereikšminga įgyvendinti ir gali būti pritaikyta sudėtingiems daugumos „iOS“ programų tinklo poreikiams. Tačiau svarbiausia yra tai, kad tinkamai suprojektuotas REST klientas ir jį lydintys komponentai, izoliuoti nuo likusios jūsų programos logikos, gali padėti išlaikyti jūsų programos kliento ir serverio sąveikos kodą paprastą, net jei pati programa tampa vis sudėtingesnė. .

Tikiuosi, kad šis straipsnis jums bus naudingas kuriant kitą „iOS“ programą. Galite rasti šio tinklo modulio šaltinio kodą „GitHub“ . Patikrinkite kodą, išsišakokite, pakeiskite, žaiskite su juo.

Jei manote, kad kita architektūra yra labiau tinkama jums ir jūsų projektui, pasidalykite išsamia informacija toliau pateiktame komentarų skyriuje.

Susijęs: RESTful API naudojimo ir duomenų patvarumo „iOS“ supaprastinimas naudojant „Mantle“ ir „Realm“