RubyMotion är ett ramverk som låter dig bygga iOS-applikationer i Ruby. Det ger dig alla fördelarna med Ruby-språket, men för att din kod är sammanställd till maskinkod får du all den råa prestanda som utvecklas i Objective-C. RubyMotion låter dig använda iOS SDK direkt, vilket innebär att du har tillgång till alla de senaste funktionerna på plattformen. Du kan inkludera Mål-C-kod i ditt projekt och RubyMotion fungerar även med CocoaPods.
I den här handledningen bygger du en målningsprogram från början. Jag ska visa dig hur du integrerar gränssnittsbyggare i ditt arbetsflöde och hur du testar din ansökan korrekt. Om du inte har någon tidigare iOS- eller Ruby-upplevelse, rekommenderar jag dig att lära dig mer om de första. Tuts + Ruby for Newbies och Learning iOS SDK Development from Scratch guider är ett bra ställe att börja.
Innan du kan börja kodning måste du ha RubyMotion installerat och installerat. För mer information om hur du gör det, kolla in förutsättningarna i RubyMotion Getting Started guide.
När du har gjort det, öppna din terminal och skapa ett nytt RubyMotion-projekt genom att köra:
rörelse skapa färg cd-färg
Detta skapar en måla katalog och flera filer:
rake -T
från kommandoraden.RubyMotion genererar också a spec / main_spec.rb fil. Jag ska visa dig hur du ska testa din ansökan lite senare i den här handledningen. För tillfället kan du radera den här filen genom att köra rm spec / main_spec.rb
från kommandoraden.
Installera programmets beroenden genom att köra buntinstallation
följd av bunt exec rake
att starta din ansökan.
Woohoo! En svart skärm. Du kommer att göra det mer intressant om en minut.
Även om det är trevligt att få en löpande app, är en svart skärm lite tråkig. Låt oss lägga till en liten färg.
Precis som den inbyggda iOS SDK, tvingar RubyMotion dig inte att organisera dina filer på något visst sätt. Det är dock användbart att skapa några mappar i app katalog för att hålla ditt projekt organiserat. Kör följande kommandon från kommandoraden för att skapa en katalog för dina modeller, visningar och kontroller.
mkdir app / models mkdir app / visningar mkdir app / controllers
Ta en titt inuti app / app_delegate.rb fil:
klass AppDelegate def application (ansökan, didFinishLaunchingWithOptions: launchOptions) true end end
Om du är bekant med iOS-utveckling kommer du märka att den här metoden tillhör UIApplicationDelegate
protokoll, vilket ger flera krokar till applikationens livscykel. Observera att AppDelegate
klassen förklarar inte att den implementerar UIApplicationDelegate
protokoll. Ruby är beroende av ankstyp eftersom det inte stöder protokoll. Det betyder att det inte bryr sig om din klass säger att det implementerar ett protokoll, det bryr sig bara om det genomför de korrekta metoderna.
Definitionen av applikations: didFinishLaunchingWithOptions:
metod inuti AppDelegate
klassen kan se lite konstig ut. I Mål-C skulle denna metod skrivas så här:
- (BOOL) ansökan: (UIApplication *) ansökan gjordeFinishLaunchingWithOptions: (NSDictionary *) launchOptions;
Eftersom Metod-C-metodenamn kan delas upp i flera delar, implementerar Ruby dem på ett unikt sätt. Den första delen av applikations: didFinishLaunchingWithOptions:
är vad som skulle vara metodnamnet i MR. Resten av metoden signaturen är skriven som sökordsargument. I RubyMotion, applikations: didFinishLaunchingWithOptions:
är skrivet så här:
def ansökan (ansökan, didFinishLaunchingWithOptions: launchOptions) slut
Låt oss genomföra denna metod.
klass AppDelegate def application (application, didFinishLaunchingWithOptions: launchOptions) @window = UIWindow.alloc.initWithFrame (UIScreen.mainScreen.bounds) @ window.makeKeyAndVisible @ window.rootViewController = UIViewController.alloc.initWithNibName (noll, bunt: noll)
De första två raderna av applikations: didFinishLaunchingWithOptions:
Metod skapa ett nytt fönsterobjekt och gör det till huvudfönstret för programmet. Varför är @fönster
en instansvariabel? RubyMotion kommer skräp att samla in fönstret om vi inte lagrar det. Den sista raden i metoden sätter fönstrets root view-kontroller till en ny, tom visningskontroll.
Kör programmet för att få allt som fortfarande fungerar.
Hmm. Applikationen körs, men skärmen är fortfarande svart. Hur vet du att din kod fungerar? Du kan göra en snabb sanitetskontroll genom att lägga till följande i botten av applikations: didFinishLaunchingWithOptions:
, innan Sann
. Var noga med att ta bort det innan du går vidare.
@ window.rootViewController.view.backgroundColor = UIColor.yellowColor
Ingen ansökan är komplett utan en solid testpaket. Testning kan du vara säker på att din kod fungerar och det låter dig göra ändringar utan att oroa dig för att bryta befintlig kod.
RubyMotion skickas med en port i Bacon testbiblioteket. Om du är bekant med Rspec kommer Bacon att känna sig väldigt bekant.
För att komma igång speglar du app katalogstruktur i spec katalog genom att köra följande kommandon från kommandoraden.
mkdir spec / models mkdir spec / visningar mkdir spec / controllers
Skapa sedan AppDelegate
s specifikationsfil på spec / app_delegate_spec.rb. Enligt konventionen är källfiler speglar i spec-katalogen och har _spec bifogas till slutet av deras filnamn.
Starta denna klass genom att definiera a beskriva
block som berättar läsaren vad din fil testar.
beskriv AppDelegate göra slut
Lägg sedan till en sekund beskriva
blockera inom den första för att visa att du vill testa applikations: didFinishLaunchingWithOptions:
metod.
beskriv AppDelegate beskriva "#application: didFinishLaunchingWithOptions:" gör slutänden
Såg du på #
i början av metodens signatur? Genom konventionen börjar exempelmetoder med hash och klassmetoder börja med en period.
Lägg sedan till en specifik med en Det
blockera.
beskriv AppDelegate beskriva "#application: didFinishLaunchingWithOptions:" gör det "skapar fönstret" do UIApplication.sharedApplication.windows.size.should == 1 slutet slutet
En av de bästa sakerna om Bacon-och andra BDD-testramar-är att specifikationerna är mycket tydliga om vad de testar. I det här fallet ser du till att applikations: didFinishLaunchingWithOptions:
Metod skapar ett fönster.
Din spec behöver inte ringa applikations: didFinishLaunchingWithOptions:
metod direkt. Den heter automatiskt när Bacon lanserar din ansökan.
Kör dina programspecifikationer genom att köra bunt exec rake spec
från kommandoraden. Du ska se produktionen så här:
1 specifikationer (1 krav), 0 fel, 0 fel
Detta berättar att Bacon körde ett test och hittade inga fel. Om en av dina specifikationer misslyckas ser du 1 fel
och Bacon kommer att skriva ut en detaljerad beskrivning av problemet.
Ovanstående verk, men du ska använda UIApplication.sharedApplication
för alla dina specifikationer. Skulle det inte vara trevligt om du kunde ta tag i det här objektet en gång och använda det i alla specifikationer? Du kan med en innan
blockera.
beskriv AppDelegate beskriva "#application: didFinishLaunchingWithOptions:" gör före gör @application = UIApplication.sharedApplication avsluta det "skapar fönstret" do @ application.windows.size.should == 1 slutet slutet
Nu kan du enkelt lägga till resten av programmets specifikationer.
beskriv AppDelegate beskriva "#application: didFinishLaunchingWithOptions:" gör före gör @application = UIApplication.sharedApplication avsluta det "skapar fönstret" do @ application.windows.size.should == 1 avsluta "gör fönsternyckeln" göra @application .windows.first.isKeyWindow.should.be.true avsluta det "ställer in root view controller" gör @ application.windows.first.rootViewController.should.be.instance_of UIViewController slutänden
Kör dessa för att se till att allt fungerar innan du går vidare.
Det finns flera sätt att skapa användargränssnittet med RubyMotion. Min personliga favorit är att använda Gränssnittsbyggare med IB pärla. Öppna din Gemfile och lägg till IB-pärlan.
källa 'https://rubygems.org' pärla 'rake' pärla 'ib'
Springa buntinstallation
från kommandoraden för att installera pärlan. Om du använder Git, lägg till ib.xcodeproj
till din .gitignore fil.
Gränssnittsbyggare är en del av Xcode. Starta gränssnittsbyggaren genom att köra bunt exec rake ib: öppen
. Detta skapar ett Xcode-projekt skräddarsytt för din ansökan. Skapa en ny användargränssnittfiler genom att välja Ny> Fil ... från Xcode s Fil menyn och välj Storyboard från Användargränssnitt kategori till vänster. Klick Nästa två gånger för att slutföra detta steg.
Spara storyboardet i Medel katalog som main.storyboard. Öppna storyboardet i Xcode och dra ett nytt Visa kontrollenhet in i den från Objektbibliotek till höger. Ställ in Storyboard ID styrenhetens område till PaintingController
.
Dra en etikett i vyens kontrollvy från Objektbibliotek till höger och ange texten till Hej
.
Öppna sedan upp app / app_delegateoch ersätt den sista raden av applikations: didFinishLaunchingWithOptions:
med följande:
storyboard = UIStoryboard.storyboardWithName ("main", bunt: nil) @ window.rootViewController = storyboard.instantiateInitialViewController
Därefter kör programmets test igen med bunt exec rake spec
för att se till att de fortfarande passerar. Lägg märke till hur du inte behövde byta någon av dem? Goda specifikationer testa kodens beteende, inte dess genomförande. Det betyder att du borde kunna ändra på vilket sätt Din kod är implementerad och dina specifikationer ska fortfarande fungera. Kör din ansökan för att prova ditt nya användargränssnitt.
Vad du har byggt hittills är bra, men skulle det inte vara trevligt om din app faktiskt gjorde något? I det här avsnittet lägger du till kontrollerna för att byta färg på penseln. Skapa två nya filer, en kontroller och dess spec, genom att köra följande kommandon.
peka app / controllers / painting_controller.rb touch spec / controllers / painting_controller_spec.rb
Implementera PaintingController
s skelett tillsammans med dess spec.
klass PaintingController < UIViewController end
beskriv PaintingController gör tester PaintingController,: storyboard => 'main',: id => 'PaintingController' slutet
RubyMotion hanterar controllerspecifikationer på ett speciellt sätt. De tester PaintingController,: storyboard => 'main',: id => 'PaintingController'
rad av spec-filen berättar RubyMotion att använda kontrollenheten med ett storyboard-ID på PaintingController
i huvud storyboard. Du kan använda kontrollant
variabel för att testa den.
Därefter måste du lägga till uttag till din controller. Dessa låter dig ansluta objekt till din controller i Interface Builder.
klass PaintingController < UIViewController extend IB outlet :black_button outlet :purple_button outlet :green_button outlet :blue_button outlet :white_button def select_color(sender) end end
förlänga IB
lägger till flera metoder till din controller, inklusive utlopp
. Du har lagt till fem uttag, en för varje knapp.
Bilderna för knapparna ingår i källfilerna i denna handledning. Ladda ner bilderna och kopiera dem till Medel katalogen. Du måste regenerera ditt Xcode-projekt så att gränssnittsbyggaren kan hämta de ändringar vi har gjort. Det enklaste sättet att göra detta är att stänga Xcode och springa bunt exec rake ib: öppen
, som kommer att återuppta projektet.
Välj vykontrollen och ändra klassen till PaintingController
.
Öppna spec / app_delegate_spec.rb och ändra den senaste specifikationen för att söka efter PaintingController
klass.
det "ställer in root view controller" gör @ application.windows.first.rootViewController.should.be.instance_of PaintingController slutet
Lägg till fem knappar för vyens kontroll genom att dra Knapp föremål på utsikten från Objektbibliotek till höger.
Dessa knappar är lite tråkiga. Välj den första knappen, ändra dess typ till Beställnings
i Attribut Inspector till höger och ta bort dess titel. Var säker på Standard
tillståndet är valt i State Config rullgardinsmenyn och sätt bakgrundsbilden till button_black.png
. Ställ in Nyans egenskapen hos knappen till transparent.
Ställ in State Config rullgardinsmeny till Vald
och ändra bakgrundsbilden till button_black_selected.png
.
I Storleksinspektör, ändra bredden och höjden på knappen till 50
.
Upprepa denna process för de andra knapparna.
Nästa steg är att haka knapparna upp till utsiktsregulatorens utlopp vi förklarade tidigare. Håll ner Kontrollera tangent på tangentbordet och dra från vykontrollen till den första knappen. En meny kommer dyka upp när du släpper ut musen. Välj black_button
från menyn. Håll sedan ned Kontrollera tangenten och dra från knappen till vykontrollen och välj select_color
Metod från menyn som dyker upp. Upprepa dessa två steg för de andra knapparna.
Slutligen, välj den första knappen och klicka på Vald kryssrutan under Kontrollera i Attribut Inspector.
Nu är det bra att lägga till några användbara specifikationer till spec / painting_controller_spec.rb.
beskriv PaintingController gör tester PaintingController,: storyboard => 'main',: id => 'PaintingController' beskriver "#black_button" gör det "är anslutet i storyboardet" do controller.black_button.should.not.be.nil slutänden beskriver "#purple_button" gör det "är anslutet i storyboard" do controller.purple_button.should.not.be.nil änden beskriver "#green_button" gör det "är anslutet i storyboardet" do controller.green_button.should.not. be.nil slutet ändan beskriva "#blue_button" gör det "är anslutet i storyboard" do controller.blue_button.should.not.be.nil änden beskriver "#white_button" gör det "är anslutet i storyboard" do controller ". white_button.should.not.be.nil slutet slutet
Dessa specifikationer säkerställer att uttagen är ordentligt anslutna i Interface Builder. Som alltid är det en bra idé att köra dem innan du fortsätter för att se till att alla passerar.
Därefter implementerar du select_color
metod i PaintingController
. När den här metoden kallas väljs den knapp som valts och den tidigare valda knappen avmarkeras.
def select_color (avsändare) [black_button, purple_button, green_button, blue_button, white_button] .each do | button | button.selected = false end sender.selected = true end
Lägg till specifikationerna till spec / controllers / painting_controller_spec.rb.
beskriv "#select_color" gör innan gör controller.select_color (controller.green_button) avsluta det "avmarkerar de andra färgerna" gör controller.black_button.state.should == UIControlStateNormal controller.purple_button.state.should == UIControlStateNormal controller.blue_button.state .should == UIControlStateNormal controller.white_button.state.should == UIControlStateNormal avsluta det "väljer färg" gör controller.green_button.state.should == UIControlStateSelected slutänden
Kör programmet och kontrollera att knappvalet fungerar. När du trycker på en knapp, ska den öka i storlek. Medan det här är coolt, är det som du verkligen vill ha en färg som ska väljas när knappen trycks in. Detta är lätt att åstadkomma med några tillägg.
Sugarcube är en uppsättning iOS-tillägg för RubyMotion som gör flera uppgifter, till exempel att skapa färger, enklare. Lägg till pärla "sockercube"
till din Gemfile och springa buntinstallation
. Sen Lägg till kräver "sockercube-color"
till din Rakefile ovan Motion :: Project :: App.setup
.
Ädelstenen gör det enkelt att skapa färger med hjälp av deras hex-kod. I PaintingController
klass, lägg till följande kodsedel nedanför deklarationerna för uttag:
COLORS = ["# 333333" .uicolor, "# 7059ac" .uicolor, "# 196e76" .uicolor, "# 80a9cc" .uicolor, "#fafafa" .uicolor]
Därefter refactor arrayen av knappar i select_color
in i en privat hjälpar metod:
def select_color (avsändare) buttons.each do | button | button.selected = false end sender.selected = true @color = COLORS [sender.tag] avslutar privata def knappar [black_button, purple_button, green_button, blue_button, white_button] avsluta
Slutligen lägg till en ny metod nedan select_color
som returnerar den valda färgen.
def selected_color COLORS [buttons.find_index | knapp | button.state == UIControlStateSelected] slutet
Denna metod tar tag i indexet för den valda knappen och väljer den färg som motsvarar den. Naturligtvis skulle denna metod inte vara komplett utan test.
beskriv "#selected_color" gör innan gör controller.select_color (controller.green_button) avsluta det "returnerar rätt färg" gör controller.selected_color.should == PaintingController :: COLORS [2] änden
Kör din ansökan igen för att se till att allt fungerar som förväntat.
Du har täckt mycket av den här handledningen. Du har lärt dig hur du installerar och kör ett RubyMotion-program, du har arbetat med Interface Builder, och du har byggt ett användargränssnitt.
I den andra delen av denna handledning dyker du djupare in i modell-View-Controller-mönstret på IOS och din applikations organisation. Du lägger också till en målningsvy och skriver den kod som tillåter användaren att rita. Håll dig igång.