Introduktion til iPhone udvikling

IPhonen er et spændende stykke legetøj, komplet med en mini version af Mac OS, internet adgang, multitouch input, understøttelse af basale openGL kald og et accelerometer. Denne forholdsvis nye gadget skal der naturligvis leges med. Vi vil gerne her vise hvordan man selv får hul igennem til en “hello world” applikation på iPhone.

Opsætning af miljø

For at kunne udvikle iPhone applikationer fra en PC kræves det at man først får sat et ordentligt udviklingsmiljø op. Til dette har Apple stillet iPhone Simulator til rådighed. Simulatoren giver udviklere en virtuel iPhone til rådighed under OS X, så de derfor ikke behøver uploade deres applikation til iPhonen før hver kodetilpasning og test.

Opsætningen af miljøet er som følger:

  1. Find en Mac med OS X 10.5.5 eller nyere (kan fx. installeres som en VM under windows). Dette er i skrivende stund kravet for at kunne kører den nyeste iPhone SDK
  2. Først installeres Xcode Tools. Dette er udviklingsmiljøet (svarerende til Microsoft Visual Studio til Windows). Xcode kan findes på Install DVD’en, der følger med OS X.
  3. Bliv registreret som iPhone developer under iPhone Dev Center og download iPhone SDK.
  4. Installer iPhone SDK (men først efter Xcode installationen).
  5. Tillykke. Du har nu en virtuel iPhone på din computer. Kør programmet iPhone simulator og en iPhone vil dukke op på din skærm. Leg lidt med den inden vi går videre 🙂

Første program

Så går det løs, “Hello World” applikationen skal implementeres. Applikationen vil blot indeholde en label med tekst og en knap til at ændre denne tekst.

Først startes et nyt projekt. Dette gøres under File → New Project. Her vælges iPhone OS → Application → View-Based Application, da vi kun har brug for ét view og ingen af de ekstra features de andre muligheder giver os. Kald projektet “Hello World” og tryk OK.

Xcode laver nu selv et grundprojekt med et view tilknyttet, som nu skal udvides med den ønskede funktionalitet.

Når Xcode har generet projektet kommer “Project” vinduet frem (skulle det blive skjult igen kan der altid trykkes cmd + 0 for at få det vist på ny). Herfra vil vi som det først ændre lidt på vores applikationsbrugerflade. I “Project” vinduet gå da ind under HelloWorld → Resources og dobbeltklik HelloWorldViewController.xib. Dette starter Interface Builder Applikationen. Denne viser i vinduet View et billede af applikationsbrugerfladen, der pt blot er en uinteressant grå baggrund.

Hvis vinduet “Library” ikke allerede er åbent kan dette gøres fra Tools → Library. I “Library” ses en masse brugergrænseflade elementer, som kan trækkes over på i Interface builderen. I denne gennemgang skal vi som nævnt bruge en label og en knap, så træk disse to over i viewet.

Interface Builder

Dobbeltklik på lablens tekst og ret denne til &qout;Hello World!&qout;

Hvis vi bare ville have vores applikation til at vise en label med “Hello World”, så kunne vi være færdig nu. For at få noget kode ind, udvider vi den til ved klik på knappen at skrive “Hello Universe!”.

I HelloWorldViewController.h, fundet under “Classes” i projektmappen, udvides interface med følgende:

HelloWorldViewController.h

HelloWorldViewController.h er header filen for vores ViewController. Den første linje vi tilføjer definerer en variabel, lblHello, af typen UILabel og som er et outlet til en IO enhed. Den anden linje vi tilføjer definerer metoden, updateLabel, der skal kaldes når vores knap trykkes ned.

Nu skal vi så have forbundet vores erklærede variabel og metode med elementerne i vores interface. Derfor åbner vi igen Interface Builderen, så dobbeltklik på HelloWorldViewController.xib.

Klik på lablen og åben “Connections Inspectoren”, fra “Tools” menuen. Ud for “New Reference Outlet” ses en cirkel. Klik på denne cirkel, hold nede og træk den blå streg, der kommer frem, over til “File’s Owner” ikonet som illustreret her:

UI Element dragged to variabel

I den fremkommende menu, knyt da lablen til lblHello variablen.

På samme måde knytter vi knappen til projektet. Klik på knappen og gå ind i “Connections Inspector”. Da vi vil have noget til at ske når knappen trykkes ned, klikke vi på cirklen ud for “Touch Up Inside” eventet og trækker pilen over på “File’s Owner”, hvor vi knytter den til updateLabel metoden.

Nu skal koden skrives, som ændre lablen når knappen trykkes ned. Åben HelloWorldViewController.m fundet under “Classes” mappen. Der vil muligvis være en masse udkommenterede metoder heri, indsat af Xcode da filen blev genereret. Disse er bare metoder nedarvet fra UIViewControlleren og kan overskrives hvis man har behov for det. Vi er godt tilfredse med dem som de er, så vi ignorerer dem og udvider filen med følgende kode:

HelloWorldViewController.m

Dermed tildeles strengen “Hello Universe” til teksten i vores label.

Applikationen kan nu kompileres og køres i iPhone simulatoren.

Vælg “Simulator” som ønsket kompileringsresultat (target) og tryk “Build and Go” ikonet i toppen af “Project” vinduet for at starte applikationen.

Simulator target

IPhone simulatoren startes automatisk op af Xcode og viser det forventede resultat:

Hello World

Resourcer

iPhone Dev Center – Apple’s iPhone developer center.

iCodeBlog – Blog omkring iPhone development med gode introduktions toturials.

Et par tricks med selvmodificerende JavaScript kode

JavaScript sproget er dynamisk, hvilket vil sige at mens ens script afvikles kan alt modificeres. Har man et objekt, er det muligt at tilføje og fjerne properties på det. Sagt med andre ord er det muligt at modificere den kode der afvikles, både ved at tilføje, fjerne og overskrive funktioner samt variable.

Note: I de efterfølgende eksempler er der lagt vægt på at illustrere den selvmodificerende kode, og ikke på at opstille gyldig HTML (doctype angivelser med videre er udeladt for overblikkets skyld), og tilsvarende anvendes blot “onload” istedet for en mere korrekt cross browser metode.

De fleste kender til selvmodificerende javascript kode fra event handlers. Når et DOM elements “onclick” sættes til at pege på en javascript funktion, udnyttes faktisk blot javascript sproget selvmodificerende egenskaber:

<html>
<body>
<input type="button" id="knap" value="Tryk på mig" />
<script type="text/javascript">
function haandterKnapKlik() {
  alert("Hehe - det kilder!");
}
var knapObjekt = document.getElementById("knap");
knapObjekt.onclick = haandterKnapKlik;
</script>
</body>
</html>

I ovenstående simple eksempel sættes onclick eventhandler funktionen ved hjælp af et inline script. Det samme resultat kan opnåes med dynamisk en tilføjet funktion som her:

<html>
<body>
<input type="button" id="knap" value="Tryk på mig" />
<script type="text/javascript">
var knapObjekt = document.getElementById("knap");
knapObjekt.onclick = function () {
  alert("Hehe - det kilder osse!");
}
</script>
</body>
</html>

Fordelen ved denne metode, er at global scopet ikke bliver “forurenet” med funktionsnavne og variable. Situationen kan nemt opstå hvor der er sammenfald på navne af funktioner og variable, og det kan være ganske lumsk at debugge frem til hvor sådanne fejl er begravet, da det er helt legalt at overskrive en funktion til blot at være en simpel variabel (eller et objekt) og omvendt.

Når man skal sikre at kode kun køres en gang, kan flere strategier anvendes. Typisk ser man implementationer svarende til:

<html>
<body onload="initialiser()">
var initialiseret = false;
function initialiser() {
  if (initialiseret !== false) {
    return;
  }
  // udfør initialiseringen her ...
  initialiseret = true;
}
</body>
</html>

Der er flere problemer med ovenstående. Dels ligger funktionen “initialiser” og variablen “initialiseret” i global scopet og er dermed i fare for at blive overskrevet af andre inkluderede scripts på siden, og der er intet der forhindrer at variablen “initialiseret” senere sættes til false, hvorefter koden fint kan genafvikles.

Istedet kan anvendes en anden strategi med selvmodificerende kode som angivet herunder:

<html>
<body onload="hinnerupnet.initialiser()">
var hinnerupnet = {
  initialiser: function () {
    // udfør initialiseringen her ...
    delete this.initialiser;
  },
  variabelBar: "Hejsa",
  metodeFoo: function () {
    alert(this.variabelBar);
  }
};
</body>
</html>

Funktionen “initialiser” er her pakket ind i et objekt kaldet “hinnerupnet”. Kun selve objekt variablen “hinnerupnet” er placeret i global scope. Både funktionen “initialiser”, “metodeFoo” og variablen “variabelBar” kan dermed kun tilgåes via objektet “hinnerupnet”. Chancerne for at andre scripts på siden skulle overskrive “hinnerupnet” objektet er minimale, og bør være under programmørens egen kontrol.

Ved første kald til “hinnerupnet.initialiser()” udføres koden og der afsluttes med helt at slette funktionen fra objektet. Eventuelle efterfølgende kald til funktionen leder til en exception:

>>> hinnerupnet.initialiser is not a function

Et alternativ fremt for helt at slette en funktion er at modificere koden heri, for eksempel:

<html>
<body onload="hinnerupnet.initialiser()">
var hinnerupnet = {
  initialiser: function () {
    // udfør initialiseringen her ...
    this.initialiser = function () {
      alert("Fejl: 'hinnerupnet' objektet er allerede initialiseret!");
    };
  }
};
</body>
</html>

Første kald til “hinnerupnet.initialiser()” vil udføre den tiltænkte initialiseringskode, og slutteligt overskrive initialiseringsfunktionen således “hinnerupnet” objektet efterfølgende er:

var hinnerupnet = {
  initialiser: function () {
    alert("Fejl: 'hinnerupnet' objektet er allerede initialiseret!");
  }
};

Leg selv videre med mulighederne, de er mange!