diff --git a/assets/code/bi-bap-sample-code.xcodeproj/project.pbxproj b/assets/code/bi-bap-sample-code.xcodeproj/project.pbxproj index 593ed75..47648f3 100644 --- a/assets/code/bi-bap-sample-code.xcodeproj/project.pbxproj +++ b/assets/code/bi-bap-sample-code.xcodeproj/project.pbxproj @@ -23,6 +23,9 @@ D22D70811EB9DE91002C4A42 /* urlsessionrequest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = urlsessionrequest.swift; sourceTree = SOURCE_ROOT; }; D22D70861EB9FCB4002C4A42 /* alamofire-router.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "alamofire-router.swift"; sourceTree = SOURCE_ROOT; }; D22D70881EBA005D002C4A42 /* alamofire-sessionmanager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "alamofire-sessionmanager.swift"; sourceTree = SOURCE_ROOT; }; + D22D70AA1EBA1D0D002C4A42 /* moya-target.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "moya-target.swift"; sourceTree = SOURCE_ROOT; }; + D22D70AC1EBA2463002C4A42 /* moya-provider.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "moya-provider.swift"; sourceTree = SOURCE_ROOT; }; + D22D70AE1EBA2D1B002C4A42 /* moya-reactive-extensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "moya-reactive-extensions.swift"; sourceTree = SOURCE_ROOT; }; D2BA092E1EA4DF8B00C97E08 /* bi-bap-sample-code */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = "bi-bap-sample-code"; sourceTree = BUILT_PRODUCTS_DIR; }; D2BA09381EA4E02200C97E08 /* create-dispatch-queue.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "create-dispatch-queue.swift"; sourceTree = SOURCE_ROOT; }; D2BA09391EA4E02200C97E08 /* operation-queue-demonstration.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "operation-queue-demonstration.swift"; sourceTree = SOURCE_ROOT; }; @@ -76,6 +79,9 @@ D22D70811EB9DE91002C4A42 /* urlsessionrequest.swift */, D22D70861EB9FCB4002C4A42 /* alamofire-router.swift */, D22D70881EBA005D002C4A42 /* alamofire-sessionmanager.swift */, + D22D70AA1EBA1D0D002C4A42 /* moya-target.swift */, + D22D70AC1EBA2463002C4A42 /* moya-provider.swift */, + D22D70AE1EBA2D1B002C4A42 /* moya-reactive-extensions.swift */, ); path = "bi-bap-sample-code"; sourceTree = ""; diff --git a/assets/code/moya-provider.swift b/assets/code/moya-provider.swift new file mode 100644 index 0000000..80f89e4 --- /dev/null +++ b/assets/code/moya-provider.swift @@ -0,0 +1,9 @@ +import Moya + +let provider = ReactiveSwiftMoyaProvider() + +provider.request(.disconnectPrinter) + .filterSuccessfullStatusCodes() + .startWithResult { result in + /* zpracování odpovědi */ + } diff --git a/assets/code/moya-reactive-extensions.swift b/assets/code/moya-reactive-extensions.swift new file mode 100644 index 0000000..710ee76 --- /dev/null +++ b/assets/code/moya-reactive-extensions.swift @@ -0,0 +1,10 @@ +import Moya + +provider.request(.authorize) + .flatMap(.latest) { + return provider.request(.movePrintHead(direction: .x)) + } + .flatMap(.latest) { + return provider.request(.extrude) + } + .startWithResult { /* ... */} diff --git a/assets/code/moya-target.swift b/assets/code/moya-target.swift new file mode 100644 index 0000000..a1b2488 --- /dev/null +++ b/assets/code/moya-target.swift @@ -0,0 +1,14 @@ +import Moya + +enum Printer: TargetType { + case printFile(URL) + case disconnectPrinter + + var baseURL = /* ... */ + var path = /* ... */ + var method = /* ... */ + var parameters = /* ... */ + var parametersEncoding = /* ... */ + var sampleData = /* ... */ + var task = /* ... */ +} diff --git a/bibliography.bib b/bibliography.bib index 3f040a8..9df8668 100644 --- a/bibliography.bib +++ b/bibliography.bib @@ -226,4 +226,14 @@ @ARTICLE {github-alamofire year = "2017", note = "[cit. 2017-5-3]", url = "https://github.com/Alamofire/Alamofire" +} + +@ARTICLE {github-moya, + title = "Moya: Network abstraction layer written in Swift.", + journal = "GitHub {[online]} {[online]}", + howpublished = "[online]", + month = "květen", + year = "2017", + note = "[cit. 2017-5-3]", + url = "https://github.com/Moya/Moya" } \ No newline at end of file diff --git a/chapters/analysis-networking.tex b/chapters/analysis-networking.tex index 447c262..e4cab6a 100644 --- a/chapters/analysis-networking.tex +++ b/chapters/analysis-networking.tex @@ -10,7 +10,7 @@ \section{Síťování}\label{analyza-sitovani} \item Jednotlivé požadavky musí jít snadno řetězit bez ztráty informací či ignorování chyb. \end{enumerate} -Mým požadavkům se nejvíce přiblížili čtyři možná řešení, které následně podrobně popíši. +Mým požadavkům se nejvíce přiblížili tři možná řešení, které následně podrobně popíši. Řešení jsem analyzoval od těch nejvíce \textit{low-level}, které pracují pouze se standardními knihovnami až po implementace za využití externích knihoven. \subsection{URLSession} @@ -95,3 +95,74 @@ \subsubsection{Shrnutí} Pro zpracování je nicméně opět dostupný pouze \textit{completion blok}. Řetězení požadavků zůstává prakticky stejné jako u \textit{URLSession}. + +\subsection{Moya} + +Jako poslední možné řešení síťových požadavků jsem zvážil open source knihovnu Moya \cite{github-moya}. + +Moya je abstraktní vrstva na víše zmíněnou Alamofire. +Nabízí tedy stejné možnosti, klade si ale za cíl uživatele odstínit od správy URL adres a parametrů a dalšího nastavení. + +Druhou výhodou je zapouzdřování endpointů do tkzv. \textit{Provider} objektů. +Na rozdíl od Router objektu zapouzdřuje Provider pouze endpointy se stejnými vlastnostmi (např. stejná úroveň řízení přístupu). +Během kompilace tak lze ověřit, že požadavky, které vyžadují oprávnění jsou vytváří stejný Provider. + +\medskip + +Velmi užitečný je i zcela jiný přístup k vytváření požadavků. +Moya vytváří požadavek ve třech fázích. +Nejprve nechá uživatele vytvořit \textit{Target}, ten se následně mapuje na \textit{Endpoint} z kterého teprve Provider vytvoří samotný požadavek. + +\subsubsection{Target} + +Prvním krokem vytváření požadavku je Target. +Target reprezentuje akci, která se má vykonat na vybraném vzdáleném API. +Typicky implementovaný jako enum a poskytuje vysokoúrovňové API pro využití ve zbytku aplikace. +Implementace targetu je vidět v ukázce \ref{code:moya-target}. + +\swiftcode{code:moya-target}{Moya - Implementace Target objektu}{assets/code/moya-target.swift} + +\subsubsection{Endpoint} + +Endpoint je interní struktura reprezentující koncový bod, která je využita k sestavení požadavku. +Hlavním cílem této struktury je možnost modifikovat způsob, jakým budou požadavky vytvořeny. +Pomocí Endpoint objektu lze např. přidávat autorizační token či některé požadavky rušit, opozdit atp. + +\subsubsection{Provider} + +Při použití Moyi se veškeré požadavky odesílají skrz Provider. +Provider je generický objekt, který operuje na objektem Target. +Tím se v době kompilace dosáhne kontroly kompatibility Provider s Target objektem. + +Provider nabízí rozhraní pro modifikaci vytvoření Endpointu i pro modifikaci požadavku. +Vytvoření požadavku je vidět v ukázce \ref{code:moya-provider}. + +\swiftcode{code:moya-provider}{Moya - vytvoření požadavku}{assets/code/moya-provider.swift} + +\subsubsection{Reaktivní rozšíření} + +Moya v základu nabízí rozšíření pro použití s reaktivními knihovnami. +Díky tomu lze velmi dobře integrovat s architekturou MVVM, konkrétně do vrstvy View Model. +Usnadňuje tím také možnost řetězení požadavků pomocí flatMap operátoru jak je vidět v ukázce \ref{code:moya-reactive-extensions}. + +\swiftcode{code:moya-reactive-extensions}{Moya - Řetězení požadavků}{assets/code/moya-reactive-extensions.swift} + +\subsubsection{Testování} + +Jednou z největších výhod Moyi je možnost testování. +V Target objektu je možné definovat, jaká data má požadavek vrátit v době kdy se aplikace testuje. +Tím Moya zaručí, že testy nebudou selhávat v případě kdy nebude dostupná síť. + +Pro případ testování chování aplikace v momentě kdy je síť nedostupná nebo kdy požadavky selžou je možné opět využít úpravy Endpoint objektu. + +\subsubsection{Shrnutí} + +Moya je knihovna pro vytvoření abstrakce nad síťovou vrstvou. +Tato nová vrstva se stává jediným spojením aplikace s internetem. + +Obsahuje totožné funkce jako knihovna Alamofire, kterou ve své implementaci využívá. +Oproti Alamofire navíc nabízí striktní oddělení Endpoint a Terget objektů. + +Tím umožňuje požadavky automaticky mockovat při testování. + +Díky reaktivním rozšířením lze navíc velmi dobře integrovat s architekturou MVVM. \ No newline at end of file