.key, value: String(describing:

Asiakkaan ja palvelimen välisen logiikan eristäminen iOS-sovelluksissa



Nykyään useimmat mobiilisovellukset luottavat suuresti asiakas-palvelin-vuorovaikutukseen. Tämä ei tarkoita vain sitä, että he voivat ladata suurimman osan raskaista tehtävistään taustapalvelimille, mutta se antaa myös näiden mobiilisovellusten tarjota kaikenlaisia ​​ominaisuuksia ja toimintoja, jotka voidaan asettaa saataville vain Internetin kautta.

Taustapalvelimet on yleensä suunniteltu tarjoamaan palveluitaan RESTful-sovellusliittymät . Yksinkertaisemmissa sovelluksissa tunnemme usein houkutusta saada luomalla spagettikoodia; sekoituskoodi, joka kutsuu sovellusliittymän muun sovelluslogiikan kanssa. Kun sovellukset kuitenkin kasvavat monimutkaisiksi ja käsittelevät yhä useampia sovellusliittymiä, voi olla haittaa olla vuorovaikutuksessa näiden sovellusliittymien kanssa rakentumattomalla, suunnittelemattomalla tavalla.



Pidä iOS-sovelluskoodi siistinä hyvin suunnitellun REST-asiakasverkkomoduulin avulla.



Pidä iOS-sovelluskoodi siistinä hyvin suunnitellun REST-asiakasverkkomoduulin avulla. Tweet

Tässä artikkelissa käsitellään arkkitehtonista lähestymistapaa puhtaan REST-asiakasverkkomoduulin rakentamiseen iOS-sovellukset jonka avulla voit pitää asiakkaan ja palvelimen välisen vuorovaikutuksen logiikan erillään muusta sovelluskoodistasi.



Asiakas-palvelinsovellukset

Tyypillinen asiakas-palvelin-vuorovaikutus näyttää tältä:

  1. Käyttäjä suorittaa jonkin toiminnon (esimerkiksi napauttaa jotain painiketta tai suorittaa jonkin muun eleen näytöllä).
  2. Sovellus valmistelee ja lähettää HTTP / REST-pyynnön vastauksena käyttäjän toimintaan.
  3. Palvelin käsittelee pyynnön ja vastaa vastaavasti sovellukseen.
  4. Sovellus vastaanottaa vastauksen ja päivittää käyttöliittymän sen perusteella.

Nopealla silmäyksellä koko prosessi voi näyttää yksinkertaiselta, mutta meidän on mietittävä yksityiskohtia.



Jopa olettaen, että taustapalvelimen sovellusliittymä toimii mainostettuna (mikä on ei aina!), se voidaan usein suunnitella huonosti, mikä tekee siitä tehotonta tai jopa vaikeaa. Yksi yleinen ärsytys on, että kaikki API: lle soitetut puhelut edellyttävät, että soittajan on toimitettava tarpeettomasti samat tiedot (esim. Kuinka pyyntötiedot muotoillaan, käyttöoikeustunnus, jota palvelin voi käyttää tunnistaakseen kirjautuneen käyttäjän jne.).

Mobiilisovellusten on myös ehkä käytettävä useita taustapalvelimia samanaikaisesti eri tarkoituksiin. Yksi palvelin voi olla esimerkiksi omistettu käyttäjän todennukselle, kun taas toinen käsittelee vain analytiikan keräämistä.



Lisäksi tyypillisen REST-asiakkaan on tehtävä paljon muutakin kuin vain kutsuttava etäsovellusliittymiä. Mahdollisuus peruuttaa odottavat pyynnöt tai puhdas ja hallittavissa oleva lähestymistapa virheiden käsittelyyn ovat esimerkkejä toiminnoista, jotka on rakennettava mihin tahansa vankkaan mobiilisovellukseen.

Yleiskatsaus arkkitehtuuriin

REST-asiakkaamme ydin rakennetaan seuraaville komponenteille:



Näin kukin näistä komponenteista on vuorovaikutuksessa toistensa kanssa:



Yllä olevassa kuvassa olevat nuolet 1 - 10 esittävät ihanteellisen toimintosarjan palvelua kutsuvan sovelluksen ja lopulta pyydetyn datan mallikohteena palauttavan palvelun välillä. Jokaisella virtauksen komponentilla on erityinen rooli huolenaiheiden erottaminen moduulin sisällä.

Toteutus

Toteutamme REST-asiakkaamme osana kuvitteellista sosiaalisen verkoston sovellusta, johon lataamme luettelon kirjautuneista käyttäjän ystävistä. Oletetaan, että etäpalvelimemme käyttää JSON-vastauksia.



Aloitetaan toteuttamalla mallimme ja jäsennintämme.

Raakasta JSONista malliesineisiin

Ensimmäinen mallimme User määrittelee tiedon rakenteen kaikille sosiaalisen verkoston käyttäjille. Jotta asiat olisivat yksinkertaisia, sisällytämme vain kentät, jotka ovat ehdottoman välttämättömiä tälle opetusohjelmalle (todellisessa sovelluksessa rakenteella olisi tyypillisesti paljon enemmän ominaisuuksia).

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

Koska saamme kaikki käyttäjätiedot taustapalvelimelta sen API: n kautta, tarvitsemme tapan jäsentää API-vastauksen kelvolliseksi User esine. Tätä varten lisätään konstruktori kohtaan User joka hyväksyy jäsennetyn JSON-objektin (Dictionary) parametrina. Määritämme JSON-objektimme aliaksityypiksi:

typealias JSON = [String: Any]

Sitten lisätään konstruktori-funktio User jäsennellä seuraavasti:

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 } }

Alkuperäisen User -konstruktorin säilyttämiseksi lisäämme konstruktorin User -laajennuksen kautta tyyppi.

Seuraavaksi luodaan User objektin raaka-API-vastauksesta, meidän on suoritettava seuraavat kaksi vaihetta:

// 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)

Virtaviivainen virhekäsittely

Määritämme tyypin, joka edustaa erilaisia ​​virheitä, joita saattaa ilmetä yritettäessä olla vuorovaikutuksessa taustapalvelinten kanssa. Voimme jakaa kaikki tällaiset virheet kolmeen pääluokkaan:

Voimme määritellä virheobjektimme luettelotyypiksi. Ja kun olemme siinä, on hyvä tehdä ServiceError tyyppiä Error protokolla . Tämä antaa meille mahdollisuuden käyttää ja käsitellä näitä virhearvoja käyttämällä Swiftin tarjoamia vakiomekanismeja (kuten throw virheen heittämistä).

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

Toisin kuin noInternetConnection ja other virheitä, mukautettuun virheeseen liittyy siihen liittyvä arvo. Tämä antaa meille mahdollisuuden käyttää palvelimen virhevastausta itse virheen liittyvänä arvona, mikä antaa virheelle enemmän kontekstia.

Lisätään nyt errorDescription omaisuuden ServiceError Enumartion tehdä virheistä kuvailevampia. Lisäämme kovakoodatut viestit noInternetConnection ja other virheitä ja käytä liittyvää arvoa custom -sanomana virheitä.

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 } } }

On vain yksi asia, joka meidän on pantava täytäntöön ServiceError luettelointi. Jos kyseessä on custom virhe, meidän on muutettava palvelimen JSON-tiedot virheobjektiksi. Tätä varten käytämme samaa lähestymistapaa kuin mallien tapauksessa:

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

Sillan kaventaminen sovelluksen ja taustapalvelimen välillä

Asiakaskomponentti on välittäjä sovelluksen ja taustapalvelimen välillä. Se on kriittinen komponentti, joka määrittelee sovelluksen ja palvelimen viestinnän, mutta ei tiedä mitään datamalleista ja niiden rakenteista. Asiakas on vastuussa tiettyjen URL-osoitteiden kutsumisesta annettujen parametrien kanssa ja saapuvien JSON-tietojen palauttamisesta JSON-objekteina jäsennettynä.

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 } }

Tarkastellaan, mitä yllä olevassa koodissa tapahtuu ...

Ensin ilmoitimme luettelotyypin RequestMethod, joka kuvaa neljää yleistä HTTP-menetelmää. Nämä ovat REST-sovellusliittymissä käytettyjä menetelmiä.

WebClient luokka sisältää baseURL ominaisuus, jota käytetään ratkaisemaan kaikki sen saamat suhteelliset URL-osoitteet. Jos sovelluksemme täytyy olla vuorovaikutuksessa useiden palvelimien kanssa, voimme luoda useita WebClient -esiintymiä jokaisella on erilainen arvo baseURL

Asiakkaalla on yksi menetelmä load, joka kulkee polun suhteessa baseURL parametrina, pyyntötapa, pyyntöparametrit ja loppuun saattaminen. Suorituksen lopetus käynnistetään jäsennetyllä JSON: lla ja ServiceError parametreina. Toistaiseksi yllä olevasta menetelmästä puuttuu toteutus, johon pääsemme pian.

Ennen load menetelmällä tarvitsemme tavan luoda URL kaikista menetelmään käytettävissä olevista tiedoista. Laajennamme URL luokka tähän tarkoitukseen:

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! } }

Tässä yksinkertaisesti lisätään polku perus-URL-osoitteeseen. GET- ja DELETE HTTP -menetelmille lisätään kyselyparametrit myös URL-merkkijonoon.

Seuraavaksi meidän on pystyttävä luomaan URLRequest -esiintymiä annettujen parametrien perusteella. Tätä varten teemme jotain samanlaista kuin mitä teimme 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 } } }

Tässä luomme ensin URL käyttämällä laajennuksen konstruktoria. Sitten alustamme URLRequest -esiintymän määritä tämän URL avulla muutama HTTP-otsikko tarpeen mukaan ja lisää sitten parametrit pyynnön runkoon POST- tai PUT HTTP -menetelmien tapauksessa.

Nyt kun olemme täyttäneet kaikki edellytykset, voimme toteuttaa load menetelmä:

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 yllä oleva menetelmä suorittaa seuraavat vaiheet:

  1. Tarkista Internet-yhteyden saatavuus. Jos Internet-yhteyttä ei ole käytettävissä, soitamme valmistumisajan päättymisestä välittömästi noInternetConnection -näppäimellä virhe parametrina. (Huomaa: Reachability koodissa on mukautettu luokka, joka käyttää yksi yleisimmistä lähestymistavoista Internet-yhteyden tarkistamiseksi.)
  2. Lisää yleisiä parametreja. . Tämä voi sisältää yleisiä parametreja, kuten sovellustunnuksen tai käyttäjätunnuksen.
  3. Luo URLRequest esine, käyttämällä laajennuksen konstruktoria.
  4. Lähetä pyyntö palvelimelle. Käytämme URLSession objekti lähettää palvelimelle tietoja.
  5. Jäsennä saapuvat tiedot. Kun palvelin vastaa, jäsennämme ensin vastauksen hyötykuorma JSON-objektiksi käyttämällä JSONSerialization Sitten tarkistamme vastauksen tilakoodin. Jos se on onnistumiskoodi (ts. Välillä 200 ja 299), kutsumme JSON-objektin loppuunsaattamista. Muussa tapauksessa muunnamme JSON-objektin ServiceError: ksi -objektia ja soita valmiussulkemiselle tällä virheobjektilla.

Palvelujen määrittely loogisesti linkitetyille toiminnoille

Sovelluksemme tapauksessa tarvitsemme palvelun, joka käsittelee käyttäjän ystäviin liittyviä tehtäviä. Tätä varten luomme FriendsService luokassa. Ihannetapauksessa tällainen luokka vastaa toiminnoista, kuten ystäväluettelon saamisesta, uuden ystävän lisäämisestä, ystävän poistamisesta, ystävien ryhmittelemisestä luokkiin jne. Tämän opetusohjelman yksinkertaisuuden vuoksi toteutamme vain yhden menetelmän :

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 luokka sisältää client tyypin ominaisuus WebClient. Se alustetaan ystävien hallinnasta vastaavan etäpalvelimen perus-URL-osoitteella. Kuten aiemmin mainittiin, muissa palveluluokissa meillä voi olla erilainen esiintymä WebClient tarvittaessa alustetaan toisella URL-osoitteella.

Jos sovellus toimii vain yhden palvelimen kanssa, WebClient luokassa voidaan antaa rakentaja, joka alustaa kyseisen palvelimen URL-osoitteen:

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

loadFriends menetelmä, kun sitä kutsutaan, valmistaa kaikki tarvittavat parametrit ja käyttää FriendService: n WebClient -esiintymää tehdä API-pyyntö. Saatuaan vastauksen palvelimelta WebClient: n kautta, se muuntaa JSON-objektin User malleja ja kutsuu valmistumisen sulkemista niiden kanssa parametrina.

Tyypillinen FriendService -käyttö voi näyttää jotain seuraavalta:

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 } } } }

Edellä olevassa esimerkissä oletetaan, että funktio friendsButtonTapped kutsutaan aina, kun käyttäjä napauttaa painiketta, jonka tarkoituksena on näyttää heille luettelo kavereistaan ​​verkossa. Säilytämme myös viitteen tehtävään friendsTask omaisuutta, jotta voimme peruuttaa pyynnön milloin tahansa soittamalla friendsTask?.cancel()

Tämä antaa meille mahdollisuuden hallita paremmin odottavien pyyntöjen elinkaarta, jolloin voimme lopettaa ne, kun toteamme, että niistä on tullut merkityksettömiä.

Johtopäätös

Tässä artikkelissa olen jakanut iOS-sovelluksellesi yksinkertaisen verkkomoduulin arkkitehtuurin, joka on sekä triviaali toteuttaa että mukautettavissa useimpien iOS-sovellusten monimutkaisiin verkkotarpeisiin. Tärkein poiminta tästä on kuitenkin se, että oikein suunniteltu REST-asiakas ja sen mukana tulevat komponentit, jotka ovat erillään muusta sovelluslogiikastasi, voivat auttaa pitämään sovelluksesi asiakas-palvelin-vuorovaikutuskoodin yksinkertaisena, vaikka itse sovelluksesta tulee yhä monimutkaisempi .

Toivon, että tästä artikkelista on apua seuraavan iOS-sovelluksen rakentamisessa. Löydät tämän verkkomoduulin lähdekoodin GitHubissa . Tarkista koodi, haarauta se, vaihda se, pelaa sillä.

Jos löydät jonkin muun arkkitehtuurin, joka on suositeltavampi sinulle ja projektillesi, jaa yksityiskohdat alla olevassa kommenttiosassa.

Liittyvät: RESTful-sovellusliittymän käytön ja tietojen pysyvyyden yksinkertaistaminen iOS: ssä Mantlen ja Realmin avulla .value)) } default: break } self = components.url! } }

Tässä yksinkertaisesti lisätään polku perus-URL-osoitteeseen. GET- ja DELETE HTTP -menetelmille lisätään kyselyparametrit myös URL-merkkijonoon.

Seuraavaksi meidän on pystyttävä luomaan URLRequest -esiintymiä annettujen parametrien perusteella. Tätä varten teemme jotain samanlaista kuin mitä teimme 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 } } }

Tässä luomme ensin URL käyttämällä laajennuksen konstruktoria. Sitten alustamme URLRequest -esiintymän määritä tämän URL avulla muutama HTTP-otsikko tarpeen mukaan ja lisää sitten parametrit pyynnön runkoon POST- tai PUT HTTP -menetelmien tapauksessa.

Nyt kun olemme täyttäneet kaikki edellytykset, voimme toteuttaa load menetelmä:

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 yllä oleva menetelmä suorittaa seuraavat vaiheet:

  1. Tarkista Internet-yhteyden saatavuus. Jos Internet-yhteyttä ei ole käytettävissä, soitamme valmistumisajan päättymisestä välittömästi noInternetConnection -näppäimellä virhe parametrina. (Huomaa: Reachability koodissa on mukautettu luokka, joka käyttää yksi yleisimmistä lähestymistavoista Internet-yhteyden tarkistamiseksi.)
  2. Lisää yleisiä parametreja. . Tämä voi sisältää yleisiä parametreja, kuten sovellustunnuksen tai käyttäjätunnuksen.
  3. Luo URLRequest esine, käyttämällä laajennuksen konstruktoria.
  4. Lähetä pyyntö palvelimelle. Käytämme URLSession objekti lähettää palvelimelle tietoja.
  5. Jäsennä saapuvat tiedot. Kun palvelin vastaa, jäsennämme ensin vastauksen hyötykuorma JSON-objektiksi käyttämällä JSONSerialization Sitten tarkistamme vastauksen tilakoodin. Jos se on onnistumiskoodi (ts. Välillä 200 ja 299), kutsumme JSON-objektin loppuunsaattamista. Muussa tapauksessa muunnamme JSON-objektin ServiceError: ksi -objektia ja soita valmiussulkemiselle tällä virheobjektilla.

Palvelujen määrittely loogisesti linkitetyille toiminnoille

Sovelluksemme tapauksessa tarvitsemme palvelun, joka käsittelee käyttäjän ystäviin liittyviä tehtäviä. Tätä varten luomme FriendsService luokassa. Ihannetapauksessa tällainen luokka vastaa toiminnoista, kuten ystäväluettelon saamisesta, uuden ystävän lisäämisestä, ystävän poistamisesta, ystävien ryhmittelemisestä luokkiin jne. Tämän opetusohjelman yksinkertaisuuden vuoksi toteutamme vain yhden menetelmän :

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 luokka sisältää client tyypin ominaisuus WebClient. Se alustetaan ystävien hallinnasta vastaavan etäpalvelimen perus-URL-osoitteella. Kuten aiemmin mainittiin, muissa palveluluokissa meillä voi olla erilainen esiintymä WebClient tarvittaessa alustetaan toisella URL-osoitteella.

Jos sovellus toimii vain yhden palvelimen kanssa, WebClient luokassa voidaan antaa rakentaja, joka alustaa kyseisen palvelimen URL-osoitteen:

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

loadFriends menetelmä, kun sitä kutsutaan, valmistaa kaikki tarvittavat parametrit ja käyttää FriendService: n WebClient -esiintymää tehdä API-pyyntö. Saatuaan vastauksen palvelimelta WebClient: n kautta, se muuntaa JSON-objektin User malleja ja kutsuu valmistumisen sulkemista niiden kanssa parametrina.

Tyypillinen FriendService -käyttö voi näyttää jotain seuraavalta:

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 } } } }

Edellä olevassa esimerkissä oletetaan, että funktio friendsButtonTapped kutsutaan aina, kun käyttäjä napauttaa painiketta, jonka tarkoituksena on näyttää heille luettelo kavereistaan ​​verkossa. Säilytämme myös viitteen tehtävään friendsTask omaisuutta, jotta voimme peruuttaa pyynnön milloin tahansa soittamalla friendsTask?.cancel()

Tämä antaa meille mahdollisuuden hallita paremmin odottavien pyyntöjen elinkaarta, jolloin voimme lopettaa ne, kun toteamme, että niistä on tullut merkityksettömiä.

Johtopäätös

Tässä artikkelissa olen jakanut iOS-sovelluksellesi yksinkertaisen verkkomoduulin arkkitehtuurin, joka on sekä triviaali toteuttaa että mukautettavissa useimpien iOS-sovellusten monimutkaisiin verkkotarpeisiin. Tärkein poiminta tästä on kuitenkin se, että oikein suunniteltu REST-asiakas ja sen mukana tulevat komponentit, jotka ovat erillään muusta sovelluslogiikastasi, voivat auttaa pitämään sovelluksesi asiakas-palvelin-vuorovaikutuskoodin yksinkertaisena, vaikka itse sovelluksesta tulee yhä monimutkaisempi .

Toivon, että tästä artikkelista on apua seuraavan iOS-sovelluksen rakentamisessa. Löydät tämän verkkomoduulin lähdekoodin GitHubissa . Tarkista koodi, haarauta se, vaihda se, pelaa sillä.

Jos löydät jonkin muun arkkitehtuurin, joka on suositeltavampi sinulle ja projektillesi, jaa yksityiskohdat alla olevassa kommenttiosassa.

Liittyvät: RESTful-sovellusliittymän käytön ja tietojen pysyvyyden yksinkertaistaminen iOS: ssä Mantlen ja Realmin avulla