Opintojen meditatiivinen osuus

Viimeksi saatiin piirrettyä iPhonen ruutuun, kosketusnäytön tarkkailusta nähtiin jonkinlainen esimerkki jo aiemmin ja samalla päästiin jonkinlaiselle hajulle, miten ajastintapahtumilla (timer event) voi korvata perinteisen main loop -ajattelumallin jatkuvasti toistuvien tilannepäivitysten hoitelussa. Toisin sanoen yksinkertaisen peliapplikaation perusainekset ovat jotakuinkin kasassa.

Jottei kuitenkaan kiivettäisi perse edellä kaakaopensaaseen, pitäisi päästä edes hieman jyvälle iPhone-softan arkkitehtuurista. Järkikin sanoo (Quartz-oppaan kompatessa), ettei softaa voi vaan ruveta kasaamaan drawRect: metodiin – sen tehtävä on päivittää näytön sisältö mahdollisimman nopeasti, eikä nysväillä tilannepäivitysten tai muun yleisen säädön parissa. Olisiko itse asiassa optimaalisinta (tai edes mahdollista) naputella jopa nuo piirtokomennot graphic contextiin ihan jossain muualla ja drawRect: -metodissa vain sitten pyöräyttää läpi valmiiksi laadittu piirtosarja? En tosiaan tiedä, joku kokeneempi voisi vihjata tässä oikeaan suuntaan. No joka tapauksessa, jonkinlainen runko ja jäsentely softalle tarvitaan, vaikka se olisikin vain pikkuruinen viihdeapplikaatio – muuten virtuaaliroskis alkaa ennen pitkää rapsahtelemaan lukukelvottomiksi käyneistä lähdekoodinpätkistä.

Olio-ohjelmoinnista on kirjoitettu tuhat kirjaa ja miljoona nettiopasta, joihin ei minun asiantuntemuksellani ole mitään lisättävää, joten en ala sitä tässä kovin syvällisesti ruotimaan. Koska se kuitenkin on yksi Cocoa-kehityksen kulmakivi, hahmoteltakoon tässä sen periaatteet kuten olen ne ymmärtänyt.

Olio-ohjelmointi ottaa tietyssä mielessä mallia siitä, miten asiat toimivat todellisessa maailmassa. Esimerkiksi autolla on tiettyjä tehtäviä (eteneminen, peruuttaminen), ominaisuuksia (väri, moottorin teho) sekä käyttöliittymä (kaasupoljin, ratti), jotka yhdessä tekevät siitä auton. Esimerkiksi käsite ”Auto” olisi olio-ohjelmoinnissa luokka eli class, ja yksittäinen autoyksilö, vaikka naapurin savuttava Samara olisi luokan ”Auto” instanssi. Siis:

Auto *naapurinSamara;

Auton kuljettaja taas olisi:

Ihminen *naapurinTaisto;

Jotta nämä oliot voisivat tehdä yhdessä jotain hyödylllistä, vaikka kuljettaa Taisto kansalaisopiston huovutuskurssille, ei Taiston tarvitse eikä kuulu tietää autonsa jokaikisen osan toimintaa läpikotaisin (saatika että auton tarvitsisi tietää Taiston aineenvaihdunnan yksityiskohtia). Riittää kun Taisto tietää metodit, joilla autoa ohjataan. Samanniminen ominaisuus kahdella oliolla ei myöskään aiheuta ongelmia, kuten saattaisi käydä proseduraalisessa ohjelmoinnissa globaaleja muuttujia käytettäessä – Taiston ei siis tarvitse pelätä, että hänen painaessaan kaasupoljinta, jolloin auton ominaisuus ”kaasu” vaikka tuplaantuisi, Taiston suoliston epäonnisesti nimetty ominaisuus ”kaasu” kasvaisi samaan tahtiin aiheuttaen vaivautuneisuutta huovutuskurssilla.

Olio on siis hyvin itsenäinen otus, jonka täysipainoinen hyödyntäminen onnistuu vaikket tietäisi siitä mitään muuta kuin sen käyttöliittymässä (@interface) määritellyt julkiset metodit. Tämähän on kieltämättä erittäin kätevää, kun ohjelmointiympäristö on laajuudeltaan nykyaikaisen käyttöjärjestelmän luokkaa. Se tarkoittaa kuitenkin myös sitä, että uuden olion käyttöliittymä täytyy suunnitella hyvin ja toteuttaa erittäin pedantisti, jotta homma toimisi.

Koska olion sisäisiin ominaisuuksiin ei tosiaan muilla ole mitään asiaa, ja toisaalta niitä useimmiten kuitenkin pitää päästä muokkaamaan jotta mitään tapahtuisi, tarvitaan jokaista julkista ominaisuutta varten ”getter”- ja ”setter”-metodit. Aika puuduttavaa naputtelua, eikös? Siinä tuleekin apuun tuo aiemmin ihmettelemäni @property -> @synthesize -parivaljakko. Se luo nämä getter- ja setter-metodit automaattisesti, ja nimeää ne vakiokäytännön mukaisesti, jonka jälkeen niitä voi käyttää aivan normaalisti kuten olisit nakutellut ne koodiin itse. Myös niiden suluissa olevien lisämääritysten merkitykset selvisivät täältä (paitsi se epäatominen, jonka hatarasti ymmärsin liittyvän jotenkin moniajoon ja päällekkäisiin prosesseihin, ”threads”).

No, uuden object classin luominen (vaikkapa sen ”Auto”-classin jotain kaahailupeliä varten) ei ole mitenkään monimutkaista hommaa, kunhan seurailee oppaiden määrittelemää syntaksia. Hämärä alue alkaa omalla kohdallani edelleen siitä, missä vaikkapa nyt tuon Auto-luokan instanssit olisi järkevä luoda, ja esimerkiksi missä tarkkaan ottaen määriteltäisiin se timer action -toiminto, jolla pelin autojen sijainnit ym. ominaisuudet päivitettäisiin.

Yhdenlaisen, joskin vielä melkoisen abstraktin vastauksen tarjoaa oppaissa usein toistuva termi ”MVC” eli ”Model – View – Controller design pattern”. Äärimmilleen yksinkertaistettuna kyse on siitä, että ”Model” – ohjelman perusdata ja sen käsittelyyn tarvittavat metodit (johon tuo Auto-luokkakin kuuluisi), ”View” – eli autojen ja maiseman piirto näytölle ja käyttäjän toimien tarkkailu ja ”Controller”, eli kahden edellämainitun välillä toimiva ”komentokeskus” pidetään visusti erillään. Tämä on selvästi eräänlainen jatke olio-logiikan ”itsenäisyysperiaatteesta”, ja helpottanee erityisesti monimutkaisten ohjelmistojen kurinpitoa ja päivittämistä. Pienten ohjelmien laatimiseen periaate tuntuu kuitenkin edelleen lisäävän ylimääräistä ”byrokratiaa”. Opettelemassa kun tässä kuitenkin ollaan, koitin motivoida itseäni keksimällä periaatteesta jotain käytännön etuja, ja kyllähän niitä hetken mietinnän jälkeen löytyikin.

Ensinnäkin, jos pitäisin varsinaisen näkymän piirron erillään pelin perustoiminnallisuuksista, eli en esimerkiksi kutsuisi näytön piirtotoimintoja suoraan tuolta Auto-luokasta, vaan tämä ”Controller” välittäisi Auto-instanssien piirtämiseen tarvittavat tiedot näkymälle, niin – silloinhan voisin kokeilla näkymässä mitä vain rendaustyylejä koskematta Auto-luokkaan lainkaan. Itse asiassa pystyisin varmaan laatimaan monta rinnakkaista visutyyliä, joita voisi vaihtaa vaikka kesken pelin preferenssejä säätämällä, jolloin vaihdettaisiin vain kutsuttava näkymäinstanssi toiseen. Ihan näppärää näin pienkehittäjänkin näkökulmasta!

Viimeksi piirrettiin ruutuun luomalla UIView:lle oma alaluokka TreeniView ja määrittelemällä sen drawRect -metodi uudestaan. Olisikohan tuon UIViewController -luokan instanssi sitten hyvä paikka alkaa kasaamaan pelin ”komentokeskusta”, jossa pelidatan päivitysmetodeja ja näytön piirto- ja tarkkailumetodeja kutsuttaisiin? Pitääpä perehtyä tarkemmin… siihen asti, öitä!

Mainokset

Johan alkaa tapahtua!

Tässä vaiheessa opiskelua tulisi varmaan olla zeniläisen maltillinen ja pohdiskella muutama kuukausi luokkien, olioiden, instanssien, pointtereiden ja sensellaisten syvintä olemusta, ja käynnistää koneet vasta kun kaikki nämä käsitteet ovat omia taskuja tutummat. Eivät ole. Enkä pohdiskele. Haluan jotain näkymään ruutuun NYT!

Siispä vaihteeksi kahlaamaan iOS Dev Centeriä. Siellä on kasapäin hyviä oppaita, mutta samaa aihetta sivuavia tekstejä voi olla useampia ja jotkut niistä muistuttavat otsikkotasolla hämäävässä määrin toisiaan, joten kirjaan joitakin ylös tänne myös itselleni muistiinpanoiksi. Tämän aloitusoppaan iPhone-grafiikkaan koin itse hyödyllisimmäksi. Sen mukaan vaihtoehdot näyttivät lyhyesti sanoen olevan OpenGL ES tai Applen omat grafiikkaenginet Quartz (aka. Core Graphics), Core Animation, ja UIKit. OpenGL toi mieleen ”oikeat” 3d-pelit, joten hylkäsin sen toistaiseksi liian vaativana, vaikka oppaan mukaan sillä pystyy generoimaan myös 2d-grafiikkaa. Jos aikomuksena olisi tehdä vaativia rendauksia korkealla frameratella, tämä varmaan olisi ainoa oikea tapa, mutta kuten muistamme, tavoitehan on ihan jotain muuta – siis kääriä tukuittain rahaa köykäisillä pikkupeleillä.

UIKitin piirto-ominaisuudet taas näyttivät omiin tarpeisiini nähden äkkiseltään vähän turhankin korkean tason ohjelmoinnilta. Jos oikein ymmärsin, niin jokaikistä visuelementtiä (ympyrä, viiva, bittikarttakuva tms.) varten täytyy luoda ja hallita oma instanssinsa. Sain sellaisen mielikuvan, että tämä piirtotapa on laadittu yksinomaan toimimaan hyvin synkassa Cocoan valmiiden navigointiobjektien kanssa. Eli jos teet pääasiassa iOS:n omiin navigointielementteihin perustuvia softia, ja haluat vain hieman kustomoida jotain visua sieltä täältä, tämä tapa sopinee sinulle. Harkitsin tätä, koska näissä luokissa näytti olevan sisäänrakennettu törmäystunnistus, josta voisi olla hyötyä peleissä, mutta saavutettava framerate ei mahtaisi riittää edes pikkupelien tarpeisiin. Korjatkaa, jos olen väärässä!

Core Animation näytti ainakin tämän MoveMe-tutoriaalisoftan perusteella tukevan lähinnä ennalta määrättäviä siirtymiä, joten edes jollain asteella fysiikkaa mallintaviin pelisovelluksiin se lienee hieman kömpelö. Kaikennäköisiin näkymien välillä siirtymiin tämä framework vaikuttaisi olevan kuitenkin enemmän kuin paikoillaan, ja näitä samaisia metodeja iPhonen oma navigointi ymmärtääkseni käyttääkin.

Haluan siis piirtää melko simppeliä 2d-grafiikkaa, mutta hallita näkymää kuitenkin frame framelta. Vaihtoehdokseni näyttäisi siis jäävän Quartz 2d eli Core Graphics framework. Tämän erinomaisen oppaan perusteella Core Graphics vaikuttaisi itse asiassa aika pätevältä ja helppokäyttöiseltä grafiikkaengineltä – muunmuassa pdf-tiedostojen luonti ja Photoshopista tunnetut läpinäkyvyystilat (Multiply, Overlay jne.) näyttäisivät olevan Quartzissa sisäänrakennettuina ja muutamalla komentorivillä käytettävissä. Hyvä tietää vastaisen varalle. Juuri nyt kelpaisi silti vähempikin, vaikkapa nyt ympyrä!

Tein siis tähän tapaan (kun pari harhapolkua oikaistaan):

PS. Tuota esimerkkikoodien tulkintaa helpotti hurjasti, kun sain tietää että tuo usein toistuva omituinen syntaksi [munInstanssi munMetodi] on itse asiassa Objective-C:ssä ihan sama asia kuin itselleni paljon tutumpi munInstanssi.munMetodi -tyyli. En tiedä, josko joku sävyero on, mutta käytännössä näyttäis että noita tapoja voi käyttää miten vaan ristiin. En oikein tiedä, onko tuosta jotain suosituksia, kumpaa tapaa pitäisi käyttää.

PPS. Ai niin, ehkä jo huomasittekin, nuo Core Graphicsin komennothan olivat muuten ihan perinteisiä C-funktioita! Eli Apple koodaa itsekin muovailuvahalla silloin tällöin, vaikka ulospäin ollaan niin legoa, että.

Pelkoa ja inhoa kehitysympäristössä

Applella on valtava ja periaatteessa ihan ihmisystävälliseen sävyyn laadittu perehdytysaineisto iPhonen ohjelmistokehitykseen täällä. Lataamassani Developer-kansiossa näyttää olevan muunmuassa ohjelma nimeltä Interface Builder, jolla pystyy tekemään ihan oikean iPhone-softan näköisiä dummynäkymiä pelkästään raahailemalla navigointielementtejä paikasta toiseen. Xcode, Applen softaprojektien hallintaohjelma ja lähdekoodieditori näyttäisi ihan järkevältä. Dev Centerissä on ladattavissa hyvin dokumentoituja esimerkkiohjelmia melkein aiheesta kuin aiheesta. Jotenkin punainen lanka ei vaan löydy – kokonaiskuva Cocoa-ohjelmoinnista vilkkuu koko ajan jossakin näkökentän rajoilla mutta katoaa aina kun siihen yrittää kohdistaa katsetta.

Otetaan nyt vaikka ”Hello World” – klassinen ohjelmanpätkä, jonka olemassaolon ainoa tarkoitus on julistaa: ”Hei! Ohjelmointi on helppoa ja kivaa, ala sinäkin harrastamaan ohjelmointia!”.

Kuusnelosella naputeltiin:

10 PRINT "HELLO WORLD!"

C:llä jotain tyyliin:

int main() {printf ("Hello World");}

Ai niin, enpä muuten ole vielä kertaakaan maininnut Cocoan bestistä, siis varsinaista kieltä, jolla iPhone-ympäristössä pääasiassa koodataan. Se on Objective-C, monenlaisilla herkuilla kuorrutettu C++ -kieli.

iPhonen Hello World -applikaatio löytyy valmiina iOS Developer Libraryn Sample Code-osiosta, kätevää! Avataas… AAAARGH! Äkkiseltään laskettuna 22 eri tiedostoa, jotta ruutuun saa kirjoitettua tervehdyksen. Okei, on siinä planeetan kuva taustalla, tekstikenttä, johon saa kirjoittaa itse ja label, jossa valmis tervehdys näytetään. Alkujärkytyksen jälkeen helpottaa hieman – suurin osa tiedostoista näyttääkin olevan melko vakiomuotoisia kuvaketiedostoja, ohjelman speksiluetteloita ja muuta peruskauraa. Varsinainen toiminta näyttäisi olevan näissä ”.h” ja ”.m” -päätteisissä tiedostoissa… siis ”header” ja ”method”, kaiketi.

Kuva 3.0. Hello World -projektikansio avattuna Xcodella

Kuva 3.1. Kirjoittaja tutkimassa Hello World -sovelluksen lähdekoodia

Avaan tutuimmalta kuulostavan tiedoston eli ”main.m”: vesiperä. Siellä on vain muutama rivi koodia, joka näyttää liittyvän jotenkin muistinhallintaan, ja palautusarvona (kenelle? Steve Jobsille?) annetaan UIApplicationMain-niminen olio – eli ohjelma itse, tai ainakin joku haamu siitä? Hämärää, mutta Dev Centerin tutoriaalit vahvistavat: main-metodin muokkaaminen ei ole iPhone-hommissa se juttu. Jätän ymmärtämisen tuonnemmaksi ja yritän nyt vain etsiä sitä hemmetin ”Hello Worldia”.

Siispä seuraavien kandidaattien kimppuun: MyViewController.h ja .m. ”Näkymänhallintaa”, se kuulostaa oikealta. Avaan ensin header-tiedoston, sillä sieltähän saa nopeasti selkeän yleiskuvan, mistä on kysymys, eikös vaan?

Hmmm… skipataan alun lakitekstit. Aluksi importoidaan UIKit – sopii minulle, käyttöliittymä on ihan hyvä juttu. Sitten tehdään @interface-määrittely, jossa on tuttuja asioita (string), loogisen oloisia asioita (UITextField *textField) ja sitten ihan taikasienikamaa (<UITextFieldDelegate>, IBOutlet). Seuraavaksi määritellään kaikki uudestaan, mutta @property -tagien avustuksella, joita muuten täsmennetään vielä mm. termillä ”nonatomic” – epäatominen? Niinpä tietysti… puuh… onneksi lopussa ennen @end-määrittelyä on vielä yksi tutunnäköinen elementti:  – (void)updateString; – sehän on ihan selvästi funktio! Ei kun siis metodi, sori kaikille, olen uusi täällä.

MyViewController.m-tiedostossa pitäisi kaiken järjen mukaan vihdoin päästä moikkaamaan sitä maapalloa. Katsotaas… importoidaan headeri, käy järkeen, sitten tulee toteutusosio eli @implementation. Sitten jotakin @synthesize-tageja joilla viitataan headerista tuttuihin muuttujiin (vai instanssejako nuo nyt sitten olivat). Ei mitään käsitystä mitä tuo @property -> @synthesize tekee, mutta jonkunsortin parivaljakko se kuitenkin lienee.

Sitten se metodi. Mutta täällähän lukee ekana ”- (void) viewDidLoad {”… eihän tällaista määritelty headerissa. No, joka tapauksessa tätä metodia on nimestä päätellen tarkoitus käyttää heti näkymän ladattua – jonkinlainen alustusmetodi siis. Pitääpä katsoa koodia eteenpäin, niin nähdään missä tätä metodia kutsutaan, eikös vaan? (Te oikeat Cocoa-kehittäjät siellä, pidetään se naama ihan vaan peruslukemilla).

Sitten on määritelty se updateString-metodi, helppo nakki: stringiin tallennetaan tekstikentän sisältö ja labeliin sitten stringin sisältö. Sitten joku virtuaalinäppikseen liittyvä säätö ja sitten jotain hyvin mielenkiintoista:

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{...

Tämä selvästi liittyy kosketusnäytön tarkkailuun. Metodista löytyi kuitenkin vain kolme riviä koodia, jotka eivät tunnu liittyvän sen enempää touches- kuin event-olioonkaan. Tällä kuulemma piilotetaan virtuaalinäppis, kun käyttäjä koskettaa tekstikentän ulkopuolista näyttöpintaa: [textField resignFirstResponder]; Selvä, uskotaan. Sitten perutaan tekstikentän sisältö näin:  textField.text = self.string; Ihan järkeenkäypää. Sitten on vielä kolmas rivi, jota ei selitetä mitenkään eikä myöskään avaudu millään tasolla. [super touchesBegan:touches withEvent:event]; Esimiehelle tässä varmaan soitellaan, mutta millä asialla, miksi, ja kuka se on – beats me.

No niin, kohta varmaan päästään varsinaiseen pääkoodiin, siis siihen main looppiin, josta kaikkia näitä hienoja metodeja kutsutaan yksi toisensa perään ja sitten aloitetaan alusta. Niinhän? Niinhän?

- (void)dealloc {
  // muistin hallintaa ja instanssien nollaamista
}

… ja sitten:

@end

Muutaman hyödyttömän skrollausnapin pyöräytyksen jälkeen alistun tosiasioiden edessä. Siinä se oli, enempää ei tule. Ei mitään alkupistettä, ainakaan sellaista jota olisin pystynyt hahmottamaan. Ei mitään main loopia, joka pitäisi homman kasassa. Eihän näistä metodeista suurinta osaa edes kutsuttu missään! Eikä missään lukenut, että ”Hello, World!” Jumalauta, tämä alkaa jo olla vähän liikaa…

Tunnelmat alkavat olla sen verran ankeat, että skipataan suosiolla muutama viikko vimmaista dokumenttien plaraamista ja tutoriaalien copy/paste-tyylillä läpikäyntiä ilman ymmärryksen häivääkään, ja siirrytään suoraan nykyhetkeen. Tässä välissä on nimittäin ehtinyt tapahtua pari oivallusta, jotka ovat vihdoin johtaneet jopa jonkinlaiseen näppituntumaan Cocoa-ympäristöstä.

1. Minä mitään main loopia tartte!

iPhone on puhelin. Kyllä, näin on. Se taas tarkoittaa sitä, että sen täytyy pystyä vastaanottamaan puheluita ja viestejä ja hoitamaan monenlaisia muita askareita myös silloin kun MINUN hieno applikaationi pyörii. Ja se taas tarkoittaa, että se turhaan koodista etsimäni Main Event Loop (toki se on olemassa, ei tässä sentään mitään barbaareja olla) on tietenkin iOS:n hallussa. Tämä taas vaatii takatukka-aikakauden koodarilta ison myönnytyksen: minulla ei ole mitään keinoa tai syytäkään päästä muokkaamaan pääloopia itse – en sitä paitsi halua käräjille siitä, että tuleva hittiapplikaationi estää hätänumeroon soittamisen ja johdattaa koulubussillisen luokkaretkeläisiä surman suuhun.

Mistä siis korvaushoito tähän main loopin himoon? Eventeistä, siis tapahtumista. Kun käyttäjä sipaisee näyttöä, iOS rekisteröi tapahtuman. Kun puhelinta heilutellaan, kiihtyvyyssensori lähettää tästä tiedon ja iOS poimii taas uuden tapahtuman. Kun kuulokkeiden kaukosäätimestä lisätään volaa – tapahtuma. Jos muisti alkaa täyttyä – tapahtuma. Ja itselleni vaikeimmin oivallettava juttu oli tämä: sinun hommasi ei ole tehdä metodia joka tarkkailisi näitä tapahtumia. Sen sijaan iOS kutsuu, tiettyä komentoketjua seuraten, näitä varta vasten tapahtumiin reagointia varten laadittuja, vakiomuotoisesti nimettyjä metodeja. Nämä kutsut päätyvät automaattisesti myös sinun ohjelmallesi, ja sinun tehtäväsi onkin – oman ohjelmasi osalta – kirjoittaa näihin tapahtumiin reagointimetodit uusiksi siltä osin kun ohjelmasi toiminta sitä edellyttää. Siksi esimerkiksi tuota touchesBegan-metodia ei ollut määritelty tuolla MyViewController-headerissa – se on jo määritelty paljon syvemmällä Cocoan ytimessä, UIKit-frameworkin UIResponder-luokassa. Tämä tapa uudelleenmääritellä tiettyjä vakiotyyppisiä metodeja on ymmärtääkseni yleisemmälläkin tasolla erittäin oleellinen osa Cocoa-filosofiaa.

Mutta yksi perustarve on vielä tyydyttämättä. Kun pitäisi päästä tekemään jotain jokaisella main loopin kierroksella, vaikkapa laskemaan avaruusaluksen uusi sijainti tai laavalampun uudet värit. Tämä ei ymmärtääkseni ole mahdollista, ainakaan jailbreikkaamatta iPhoneasi. Eventit rientävät kuitenkin apuun tässäkin asiassa. On nimittäin vielä yksi tärkeä tapahtumatyyppi, jota ei ole käsitelty: ajastintapahtumat. Kaikessa yksinkertaisuudessaan, tehdään jotain aina kun iPhonen sisäinen kello on edennyt vaikka 5 millisekuntia. Tähänkin hommaan on Cocoassa omat valmiiksi pedatut metodinsa, ja niitä kannattaa käyttää.

2. Ihan sama mistä se alkaa!

Se vanhan koulun koodaajalle hirmuisen tärkeä ajatus, että mikä tässä ohjelmassa on se ihka ensimmäinen komento, ei ole Cocoa-ohjelmoinnissa kovin oleellinen. Se main.m se kai lopulta on, sitä iOS ymmärtääkseni kutsuu kun applikaation kuvaketta tupsauttaa, ja se tosiaan palauttaa iOSille applikaatioinstanssin, johon koko softa on kääritty. Mutta sillä tiedolla ei ole kummoistakaan merkitystä toimivan iPhone-ohjelman rakentamisessa. Sitä tärkeämpään asemaan nousee tuo aiemmin mainittu metodien uudelleenmäärittely -toimintatapa. Sillä kun nimittäin pääsee käsiksi kaikennäköisiin muihinkin tärkeisiin hetkiin applikaation elämässä, kuten siihen kun ohjelman eka näkymä on latautunut loppuun (jolloin voisi esimerkiksi alustaa muuttujia).

3. Kaikkea ei tarvitse tehdä itse

iPhone-kehittäjä: et ole Rambo! Sinun ei tarvitse lahdata kaikkia pahiksia yksin. Olet pikemminkin Rusty Robottipoika, jonka tärkein tehtävä on päästä Ison Hepun (iOS) kyytiin – kun pidät tiukasti kiinni etkä ala ryttyilemään isommallesi, olet aika lailla turvassa.

Eli käytännöllisemmin: kun alat suunnittelemaan jotain toiminnallisuutta uuteen softaasi, älä turhaan tuhlaa aikaasi miettimällä, miten tämän asian ratkaisisit – katso sen sijaan ensi töiksesi iOS  Frameworks -listauksesta missä määrin ja miten Cocoa on jo ratkaissut asian, ja miten sitä ratkaisua tulisi jalostaa, jotta käsillä oleva ongelma ratkeaisi.

Valtavasti maastoa on vielä kartoittamatta, mutta nyt ainakin kartta on jo oikeinpäin kädessä. Seuraavaan kertaan!

Kuva 3.3. iPhone-sovelluskehittäjä ja iOS yhteiskuvassa

Kuva 3.2. Selvästikään ei iPhone-kehittäjä

10 GOTO ObjectOrientation;

Perinteinen, proseduraalinen ohjelmointi on kuin muovailuvahalla askartelua: kun olet päättänyt mitä ohjelmasi pitäisi tehdä, alat vain muovailla sellaisia ominaisuuksia kuin tarvitset.

Kuva 2.0. Perinteinen ohjelmointi

Kuva 2.1. Olio-ohjelmointi

Kuva 2.2. Cocoa

Objektiorientoitunut ohjelmointi – jonka joku valopää aikoinaan keksi lanseerata Suomeen nimellä ”olio-ohjelmointi” – on taas pikemminkin kuin Legoilla rakentelua:  kokonaisuus muodostuu yhdistelemällä tarkkaan standardoituja palikoita, joista kukin on vastuussa jostakin ohjelmasi osa-alueesta.

Sitten on Cocoa, siis Applen ohjelmistokehitysrunko, jonka varaan kaikki Mac- ja iPhone-ohjelmat on rakennettu. Jatkaaksemme vertausta, Cocoan voisi hahmottaa jättiläismäiseksi legosiiloksi, joka sisältää lukemattoman määrän palikoita Duploista Lego Technic -sähkömoottoreihin ja hydrauliikkapumppuihin.

Älä siis yritä tehdä Apple-softaa muovailuvahasta – usko pois, siitä ei tule mitään. Muovailuun tottuneen ohjelmoijan voi olla vaikea uskoa, että legoilla voisi mitenkään saada aikaan yhtä fiiniä jälkeä. Ja totta onkin, että varsinkin jos tavoitteesi on pieni ohjelma joka tekee jotain täysin omalaatuista lähellä hardware-rajapintaa – kuten vaikkapa demo – olio-orientoituneisuus teettää aika lailla lisävaivaa.

Kuva 2.3. Legoland: kyllä. Vahalandia: ei.

Vaikka tällaisella vanhan koulun oppeihin nojaavalla harrastelijakoodarilla  kului joku tovi tämän myöntämiseen, Cocoa ei kuitenkaan perustu oliofilosofialle silkasta brassailun halusta. Legopalikoista vaan on helpompi tehdä isoja, täsmällisesti toimivia kokonaisuuksia kuin muovailuvahasta. Vai oletteko ikinä kuulleet Vahalandiasta?

Okei, nöyrryn, kumarran Oliota ja myönnän että se on ainoa oikea tie valaistumiseen. Jäljelle jää enää yksi kysymys: mitä tämä Cocoa oikein minusta haluaa?

Koodaustaidot 2000-luvulle

Olen kolmekymppinen graafinen suunnittelija, joka monen muun tavoin iPhonen App Storea ja eräiden vihaisten lintujen menestystarinaa ihmeteltyään alkoi haaveilla, että josko sitä itsekin keksisi jonkin killer appin ja turvaisi eläkepäivät palatsissa Aruballa. No, kulttisuosiota nauttiva niché-applikaatio ja viikonlopun juomarahatkin kelpaisivat.

Kuva 1.0. Graafinen esitys kirjoittajan lähtötilanteesta

Ulkoasu hoituisi ja tuttavapiiristä saisi varmaan manguttua audiopuolen tekijät – näin ollen ainoa puuttuva yksityiskohta (idean lisäksi) on toteutus. Mikä voisi mennä vikaan? Siis ei muuta kuin opettelemaan!

Olen viimeksi ohjelmoinut teini-iässä C:llä, kun MS DOS oli vielä kova sana, ja Windows oli joku omituinen toimistotyyppien käyttämä lelu. Macintosheja oli toki jo olemassa, mutta ei meidän universumissamme. Tein yhden tunneliefektin ja yhden (kesken jääneen) pelin, jossa ammuttiin avaruusporoja pikseleillä. Näiltä pohjilta pitäisi sitten oppia iPhone-ohjelmointi ja mieluiten tulla miljonääriksi.

TV-sarja Aikahyppy (Quantum Leap) on aika osuva analogia tilanteestani – aikamatkustus-aiheen lisäksi myös siksi, että sitä esitettiin alunperin suurinpiirtein samoihin aikoihin, kun viimeksi naputtelin lähdekoodia. Sarjan päähenkilöhän oli tiedemies Sam Beckett, joka havahtui joka jakson alussa eri aikakaudella ja eri henkilön ruumiissa tehtävänään ratkaista jokin ”isäntähenkilönsä” ongelma. Minun tapauksessani Sam Beckett tosin näyttäisi varmaan lähinnä taannoisten Apple-mainosten ”I’m a PC” -mieheltä, joka heräisi kauhukseen vuodessa 2011 sen  ”I’m a Mac” -tyypin virnuillessa peilissä. Ja iPhone-applikaatio pitäisi saada aikaan keinolla millä hyvänsä.

Tämän vuosituhannen puolella töitä tehnyt ammattikoodari saanee näistä kirjoituksista irti yhtä paljon kuin Tuksun blogista. Oivaltavia pro-vinkkejä on siis melko turha odottaa – tämän blogin mahdollinen arvo lienee vertaistuki samankaltaisessa tilanteessa olevien kesken ja niiden poikkeuksellisen tyhmien kysymysten ratkominen, joihin dev centerien oppaat eivät vastaa.