Poniższy wpis jest gościnnym tekstem Tomasza Bąka – iOS dewelopera w firmie App'n'roll. Artykuł został pierwotnie opublikowany w serwisie Medium w języku angielskim. Zachęcam do prześledzenia innych publikacji autora oraz zostawienia komentarza, czy chcielibyście, aby na MyApple pojawiało się więcej tego typu materiałów.

Podczas tegorocznego WWDC Apple zaprezentowało Xcode Source Editor Extensions, nowy i łatwy sposób na poszerzenie możliwości naszego ulubionego narzędzia. Jeśli jesteś ciekawy w jaki sposób ujarzmić jego moc, aby uczynić cię bardziej produktywnym, czytaj dalej.

Wielu liderów w branży tworzenia oprogramowania wierzy, że nasza profesja jest formą rzemiosła. Jeden aspekt tej metafory jest wyjątkowo trafny - narzędzia. Świetny rzemieślnik potrzebuje świetnych narzędzi, ale nie zapominajmy o przysłowiu “Złej baletnicy przeszkadza nawet rąbek u spódnicy”.

Christoph Gockel przypomina nam, że powinniśmy wybierać odpowiednie narzędzia do odpowiedniej pracy, ale jeśli takich nie znajdujemy, to powinniśmy stworzyć własne. To dokładnie będziemy dziś robić. Xcode miał w przeszłości obfitość wtyczek stworzonych przez osoby spoza Apple. W przeszłości, ponieważ Xcode 8 nie będzie ich już wspierać. To smutna wiadomość, ale twórcy mieli bardzo dobre powody (związane z bezpieczeństwem i niezawodnością), aby tak to rozwiązać.

Apple wie również, że programiści nie lubią próżni i aby powstrzymać nas od zrobienia czegoś nieodpowiedzialnego, jak usunięcie autoryzacji pliku binarnego IDE, dają nam nowy sposób na własnoręczne budowanie narzędzi. Prezentacja na WWDC daje bardzo dobry opis nowych możliwości, ale w App’n’roll wiemy, że najlepszy sposób na naukę to praktyka.

Model z JSONa

Wielu z was pracuje z siecią w swoich aplikacjach i od czasu do czasu musicie zparsować JSONa i napisać dla niego model. To zadanie, które z łatwością mogłoby wykonać dla nas IDE, więc zdecydowaliśmy się w tym celu napisać rozszerzenie. Aby nie komplikować nadmiernie spraw, postanowilśmy zrobić kilka założeń. Po pierwsze, oczekujemy, że obecnie edytowany plik jest JSONem. Po drugie, będziemy ignorować warunki krańcowe przy parsowaniu zagnieżdżonych obiektów.

Uwaga!: Nasz przykład został napisany w Xcode 8.0 beta 2, więc może nie zawsze działać zgodnie z oczekiwaniami. Jeśli wciąż pracujesz na na El Capitan, postępuj zgodnie z instrukcjami z Xcode 8.0 beta Release Notes - Known Issues in Xcode 8.0 beta — IDE, Source Editor Extensions. Pamiętaj także, aby być cierpliwym przy uruchamianiu roszerzenia. Jeśli otworzysz projekt za szybko - zanim rozszerzenie się załaduje - nie będzie ono dostępne z poziomu menu testowej instancji Xcode’a.

Rozpocznijmy od stworzenia nowego projektu na macOS (pamiętaj o zaznaczeniu checkbox’a o dodaniu testów jednostkowych) i dodania nowego target’u do domyślnego szablonu aplikacji - Xcode Source Editor Extension:

Ten szablon stowrzy dla nas Info.plist i dwie nowe klasy. Zanim zagłębimy się w kodzie, spójrzmy najpierw na Plist. Aby zmienić nazwę wyświetlaną w menu Xcode’a musimy podmienić Bundle Name i XCSourceEditorCommandName.

Pierwsza z wygenerowanych dla nas klas implementuje XCSourceEditorExtension i będzie nas powiadamiać kiedy rozszerzenie zostanie załadowane. Nie będziemy edytować tego pliku w naszym przykładzie. Druga klasa implementuje XCSourceEditorCommand — protokół z tylko jedną metodą— perform (with invocation:, completionHandler:), która zostanie wywołana, kiedy uruchomimy polecenie. Rozszerzenie dostarczy nam zawartość plik i możliwość jego edycji. Napiszemy prostą warstwę abstrakcji, aby umożliwić przetestowanie naszej logiki. Nasza interakcja z plikiem zostanie oganiczona przez protokół SourceFile:

Naszym następnym krokiem jest stworzenie obiektu pomocniczego, który będzie łatwy do przetestowania. Nazwijmy go JSONConverter:

Ma on tylko jedną metodę, która przyjmuje SourceFile i generuje wyjątek jeśli coś pójdzie nie tak. Integracja z XCSourceEditorCommand wymaga prostego adaptera i wygląda następująco:

Po uruchomieniu rozszerzenia i wykonaniu polecenia nic się nie dzieje - dokładnie jak oczekiwaliśmy. Najwyższy czas na TDD. Wpierw musimy zainicjalizować obiekt poddawany testowaniu i napisać test double dla SourceFile:

Nasz pierwszy test sprawdza parsowanie błędnego JSONa:

...a tutaj mamy kody, który naprawi test:

Następnym krokiem jest zparsowanie prostego JSONa z jednym String’iem: Oto test:

… a to implementacja:

Teraz będziemy trochę oszukiwać - napiszemy trzy testy na raz dla różnych wariantów NSNumber:

… oraz zaimplementujemy wszystkie trzy fukcjonalności na raz. Kod sprawdza typ obiektu w czasie wykonywania programu i używa dla niego odpowiedniego typu Swift’owego:

Następnym naszym punktem są listy. Tutaj test:

…i implementacja:

Ostatnim typem, który chcemy wspierać jest typ zagnieżdżony. Najprostszy możliwy test nam to zilustruje:

Typ zagnieżdżony wymaga, więc zmian niż pozostałe przypadki, więc zamieszczamy od razu gotowy kod do JSONConverter:

To wszystko. Musimy naprawić część testów po zmianach w nazewnictwie modeli. JSONConverter jest już zintegrowany z XCSourceEditorCommand, więc nie pozostaje nam nic innego jak sprawdzić czy wszystko działa w Xcode.

Gratulacje, właśnie ukończyłeś/-aś swoje pierwsze rozszerzenie Xcode’a.

Podsumowanie

Dobieranie narzędzi to jeden z najważniejszych obszarów dla każdego programisty. Nasi dostawcy IDE nie zawsze dają na to czego potrzebujemy, więc czasami musimy wziąć sprawy w swoje ręce. Rozszerzenia Xcode’a są świetnym miejscem, aby nauczyć się jak to robić.

W tym momencie nie mamy wielu możliwości, ale znająć Apple, to dopiero pierwszy krok i kiedy otrzymamy dostęp do AST i systemu plików w projekcie - hulaj dusza, piekła nie ma. Wszystkie źródła naszego projektu możesz znaleźć na Githubie.

Zapraszamy również do działu Dla Programistów na naszym forum.