Swift Playgrounds-appen til iPad har altid været en smule splittet mellem to vidt forskellige slags anvendelsesområder. På den ene side blev den tydeligvis bygget med et primært fokus på uddannelse og på at være et godt værktøj for begyndere – men på den anden side fungerer den også som den eneste måde for professionelle udviklere at køre Swift-kode lokalt på deres iPad.
Interessant nok sætter det på en måde Swift Playgrounds i en meget lignende position som iPad’en som helhed – i den forstand, at den både skal imødekomme afslappede og simple brugstilfælde, samt fungere som et kompetent værktøj for mere avancerede, især i lyset af den stigende popularitet af iPad Pro som en komplet computerplatform.
I denne uge skal vi se på, hvor godt den nye 3.0-version af Swift Playgrounds klarer denne balance mellem enkelhed og kraft, og hvordan nogle af de nye funktioner virkelig forbedrer de måder, hvorpå det kan bruges som et meget bærbart, avanceret Swift-udviklingsværktøj.
Instabug: Løs fejl, nedbrud og andre problemer meget hurtigere ved hjælp af de detaljerede stack-traces, netværkslogfiler og UI-hændelser, som Instabug automatisk knytter til hver fejlrapport. Bruges både af mig og af tusindvis af iOS-udviklingshold rundt om i verden. Prøv det gratis, og integrer det med blot en enkelt linje kode.
Arbejde, leg og uddannelse
Det tager ikke lang tid at indse, at hovedformålet med Swift Playgrounds er at tjene som et værktøj for studerende, undervisere og for folk, der vil begynde at lære at kode. Lige når man åbner appen, præsenterer den tydeligt forskellige kodningslektioner og læringsudfordringer – og alt lige fra det sprog, der bruges til menupunkter og kommandoer, til appens udgivelsesnoter i App Store har et klart uddannelsesfokus.
Når man imidlertid åbner en tom legeplads og begynder at kode, har appens faktiske muligheder altid været ganske imponerende – lige fra den måde, den giver fuld adgang til iOS SDK og Foundation, til hvordan den lader os rendere visninger og view controllers nativt ved hjælp af PlaygroundPage.current.liveView
, til kompilerens hastighed – især på de nyeste iPad Pro-modeller.
Version 3.0 tilføjer også nogle meget velkomne forbedringer til blandingen. Til at begynde med er compileren nu blevet opdateret til Swift 5.0-versionen, og den overordnede stabilitet i editoren og den måde, den interagerer med compileren på, er også blevet forbedret. Når der opstår et nedbrud eller en kørselsfejl, viser appen ikke længere en simpel advarselsvisning, der fortæller, at noget gik galt, men præsenterer i stedet fyldige fejlmeddelelser ved siden af den kodelinje, der forårsagede fejlen – og kompileringsfejl vises nu på en “Issues”-liste i lighed med den, der findes i Xcode.
Moduler gjort let
Den måske største forbedring for udviklere, der ønsker at bruge Swift Playgrounds som et egentligt udviklingsværktøj, er den tilføjede understøttelse af moduler, der indeholder flere kildefiler. Swift-moduler er i det væsentlige den “rene Swift”-ækvivalent til et bibliotek eller en ramme, og den måde, de er blevet integreret i Playgrounds-appen, er ganske enkelt fantastisk.
Det nye dokumentikon kan nu findes i øverste venstre hjørne af editoren – og ved at trykke på det åbnes en popover, der giver os mulighed for at gennemse og ændre den aktuelle playgrounds kildefiler og moduler. Både nye filer og nye moduler kan tilføjes med et par tryk på, og enhver ny kildefil åbnes automatisk som en ny fane i editoren. Det er problemfrit, hurtigt og gør det trivielt at begynde at opdele et større stykke kode op i separate moduler. Hvert modul importeres også automatisk til legepladsen, mens der stadig kræves eksplicit import mellem modulerne.
Sammenlign ovenstående med, hvor mange trin det tager at tilføje en ny Swift-ramme i Xcode.
Modularisering kan ofte være nøglen for at gøre det lettere at vedligeholde et projekt – især når mængden af funktioner og kildefiler vokser. Ved at dele tingene op i separate moduler med hver sit ansvar og domæne kan vi både sikre en rimelig grad af adskillelse af bekymringer – og også nemt identificere arkitektoniske problemer, f.eks. når to forskellige kodestykker er for stærkt koblet, eller når en visning gør for mange antagelser om de data, som den gengiver (da det nu ville kræve import af et andet modul at få adgang til sådanne oplysninger).
Moduler giver os også mulighed for at gøre brug af internal
adgangskontrolniveauet og gøre typer og funktioner, der kun er beregnet til intern brug inden for et modul, utilgængelige uden for dette modul. Da internal
er standardtilgangsniveauet i Swift, betyder det også, at vi udtrykkeligt skal markere de typer og funktioner, som vi ønsker at sælge som en del af vores moduls offentlige API, som public
. Selv om nogle udviklere måske vil betragte det som lidt af en “pligt”, tvinger det os på en måde til at vænne os til at designe mere klare og veldefinerede API’er.
Xcode-kompatibilitet
Selv om Swift Playgrounds nu har fået en masse kraft og flere nye funktioner, der gør det til et langt mere kompetent udviklingsværktøj, er det langt fra en komplet Xcode-erstatning for de fleste anvendelsestilfælde – og det forsøger det heller ikke engang at være. Der er gode grunde til, at det hedder “Swift Playgrounds” og ikke “Xcode for iPad” (selv om vi forhåbentlig også får sidstnævnte at se på et tidspunkt). Det er et værktøj til at lege med idéer, til at lave let kodning på farten og til at bygge prototyper og isolerede moduler – snarere end at være et komplet IDE med støtte til komplekse projekter.
Så eftersom Swift Playgrounds – for de fleste udviklere – højst sandsynligt vil fungere som et supplement til Xcode snarere end en erstatning, hvor nemt er det så at flytte projekter og kode mellem de to? Svaret er desværre, for det meste, ikke så let. Selv om apps som Working Copy (disclaimer: tidligere sponsor) og værktøjer som Shapeshift (disclaimer: skrevet af mig) gør det ganske trivielt at flytte egentlig kildekode mellem Mac og iPad – er der desværre meget lidt direkte kompatibilitet mellem Swift Playgrounds og Xcode.
For starters, they use different file formats. Xcode bruger stadig det .xcodeproj
bundle-format, som det har brugt i årevis, og selv om Xcode-skabte .playground
-filer kan åbnes på iPad, bruger de playgrounds, der oprettes i selve Playgrounds-appen, det iPad-beskyttede .playgroundbook
-format.
Det eneste, som Xcode 10 kan gøre med Swift Playgrounds-bøger, er at vise et ikon – forhåbentlig ændres det til dette års WWDC.
Det betyder, at selv om vi nu nemt kan oprette moduler og filhierarkier på iPad, så skal vi, når vi ønsker at flytte vores kode tilbage til Mac’en (hvilket vi på et tidspunkt er nødt til at gøre, hvis vi bygger en app), omorganisere koden til noget, der er Xcode-kompatibelt – f.eks. ved at tilføje filer til Xcode-projekter og oprette rammer til vores moduler.
Håbentlig vil fremtidige versioner af både Swift Playgrounds og Xcode bringe et mere normaliseret projektformat (hvor fantastisk ville det ikke være, hvis alle Apples udviklerværktøjer brugte Swift Package Manager og dets Package.swift
-manifest til at definere projekter?), hvilket vil gøre det meget nemmere at overføre hele projekter til og fra iPad – hvilket potentielt vil åbne op for endnu mere avancerede anvendelsesmuligheder og gøre det muligt for os at redigere hele apps på farten.
Mulighed for testbarhed
Et andet aspekt af Swift-udvikling, som Swift Playgrounds på iPad i høj grad mangler, er understøttelse af enheds- og UI-tests. Ikke alene tilbyder appen ikke nogen form for indbygget måde at køre tests på, den leveres ikke engang med den XCTest
ramme, som de fleste Swift-udviklere er afhængige af, når det drejer sig om nogen form for automatiseret testning.
Så betyder det, at det er helt udelukket at skrive tests på iPad? Heldigvis ikke. På trods af alle sine begrænsninger rummer Swift Playgrounds stadig den komplette Swift-kompiler, og da XCTest
– i sidste ende – ikke er andet end kode, kan vi ganske let genimplementere nogle af de centrale aspekter af den direkte i selve Swift Playgrounds!
(Det ville ikke være en Swift by Sundell-artikel uden nogle kodeeksempler, vel? 😉)
Lad os starte med at definere en “trimmet” version af XCTestCase
-klassen, men som en protokol i stedet. Vi vil kræve, at alle testcases har en tom initialisator (så vi dynamisk kan oprette instanser), metoder til opsætning og nedrivning af hver testkørsel, samt en Swift Package Manager-inspireret allTests
-egenskab for at give vores testkører adgang til hver testmetode, som vi ønsker at køre:
protocol XCTestCase { init() func setUp() func tearDown() static var allTests: { get }}
Mens vi kunne have implementeret XCTestCase
som en konkret klasse i stedet og gøre brug af Objective-C-køretiden til at identificere testmetoder – ligesom XCTest
selv gør det på Apple-platforme – ville det kræve, at vi skulle markere hver metode med @objc
, og det ville også gøre vores kode mindre portabel, hvis vi ønsker at implementere den på platforme som Linux.
Næst skal vi udvide vores XCTestCase
-protokol med en metode, der lader os køre en given testcase (ved at opregne alle dens metoder og kalde hver enkelt), samt tomme standardimplementeringer af setUp
og tearDown
:
Med ovenstående på plads er vi nu i stand til at definere testcases, men vi har også brug for en måde at udføre verifikationer og assertions på, når vi skriver vores egentlige testlogik. For at lette dette starter vi med at implementere funktionen XCTFail
, som lader os fejle en test, hvis en bestemt betingelse ikke blev opfyldt. Vi giver den et valgfrit reason
-argument, og vi registrerer automatisk navnet på den testfunktion, hvor den blev kaldt, samt linjenummeret – som her:
Med ovenstående kan vi nu implementere XCTAssertEqual
-funktionen, som lader os bekræfte, at resultatet af en operation viste sig at være lig med det resultat, vi forventede:
Det er egentlig alt, hvad vi behøver for at begynde at skrive nogle grundlæggende tests. Her er for eksempel hvordan vi nu kunne verificere en, at en Playlist
type holder korrekt styr på sine sange, samt sikre os, at dens serialiseringskode fungerer som forventet:
For at køre vores ovenstående test kalder vi blot run()
på testtilfældens type:
try PlaylistTests.run()
Det er måske ikke en komplet genimplementering af XCTest
, og vi skal blive ved med at tilføje hver enkelt assertion-funktion og testfunktion, som vi får brug for manuelt – men det viser, at mange forskellige avancerede udviklingsfunktioner er teknisk mulige på iPad – nogle gange skal vi bare bruge lidt tid og kreativitet for at få dem til at ske.
Support Swift by Sundell ved at tjekke denne sponsor:
Instabug: Løs fejl, nedbrud og andre problemer meget hurtigere ved hjælp af de detaljerede stack-traces, netværkslogfiler og UI-hændelser, som Instabug automatisk knytter til hver fejlrapport. Bruges både af mig og af tusindvis af iOS-udviklingshold rundt om i verden. Prøv det gratis, og integrer det med blot en enkelt kodelinje.
Konklusion
Den 3.0-version af Swift Playgrounds til iPad er en fantastisk opdatering af en allerede dejlig app – som tilføjer kraftfulde nye funktioner og gør centrale udviklingsfunktioner, som f.eks. fejlrapportering, meget bedre – alt imens den stadig har fokus på brugervenlighed og pædagogisk indhold.
Swift 5, moduler, redigering med faneblade og styring af kildefiler er alle fantastiske funktioner, der gør denne version af Swift Playgrounds til den mest kompetente hidtil – og det er et stort skridt i retning af at gøre det muligt at udføre mange flere Swift-udviklingsopgaver på iPad. Ligesom når det gælder arbejdet på iPad generelt, kræver brugen af Swift Playgrounds nogle gange lidt ekstra tålmodighed og omgåelser, men resultatet kan ofte give et kraftfuldt udviklingsmiljø på en meget bærbar enhed.
Swift Playgrounds er stadig ikke en “Xcode-dræber”, og det bliver det nok aldrig, men det er helt i orden. Selv om bedre interoperabilitet med Xcode (især med hensyn til filformater og projektstruktur) og mere avancerede editorfunktioner (som f.eks. værktøjer til refaktorering og tekstudskiftning) bestemt ville være mere end velkomne, så længe jeg hurtigt kan skrive Swift-kode på farten, er jeg mere end tilfreds – i hvert fald mens jeg venter på, at “Xcode for iPad” kommer.
Skriv et svar