Sprachkürzel: deSprachkürzel: en
qW-Logo Ratgeber | Programmieren | Mac OS X
Downloads | iPhone | Webrauschen | Impressum
Sprachkürzel: de
Objective-C fürs iPhone (10.09.09) (2009-02-18 | 23:02) - 3701 Besucher

Hier sind meine Erfahrungen und Gedächtnisstützen zur Programmierung von Objective-C mit Xcode für das iPhone und den iPod Touch (2nd gen)

Für alle hier vorgestellten Routinen und Funktionen wird keine Garantie auf Funktion übernommen!

Zu Beginn ein Hinweis...

Um xCode auf MultiCore oder MultiProzessor-Macs zu beschleunigen, kann es helfen, die maximaler Threadanzahl zu erhöhen... Das geht im Terminal mit diesem Befehl:

defaults write com.apple.Xcode PBXNumberOfParallelBuildSubtasks "anzahl threads" ↵

Eine Klasse erstellen

Hiermit wird eine Klasse erstellt...

@interface quadWorksController : UIViewController
{
    UIButton   *button;
}
@end

Die Prozeduren werden dann so gefüllt...

@implementation quadWorksController
- (void) setthetitle : (NSString *) sender
{
    [button setTitle:sender forState:UIControlStateNormal];
}
@end

 

Funktionen innerhalb der Klasse aufrufen

Die Funktion wird wie folgt deklariert:

- (void) setthetitle : (NSString *) sender
{
    [button setTitle:sender forState:UIControlStateNormal];
}

Der Aufruf geschieht dann über:

[self setthetitle:(@"test!")];

Aus einer fremden Prozedur muss der Aufruf unter Angabe des aufzurufenden Objekts erstellt werden:

[quadWorksController setthetitle:(@"test!")];

 

Eine Zahl in einen String konvertieren

String werden im Format NSString angegeben. Die Funktion stringWithFormat wandelt ein Int in einen String um, hier sind es 4 Stellen vor und 2 Stellen nach dem Komma...

[NSString stringWithFormat:@"%4.2f", x]

 

Horizontalmodus forcieren

Das iPhone muss quer gehalten werden...

application.statusBarOrientation = UIInterfaceOrientationLandscapeRight;

Status- oder Navigationsleiste verstecken

[[UIApplication sharedApplication] setStatusBarHidden:YES animated:NO];

[[UIApplication sharedApplication] setNavigationBarHidden:YES animated:NO];

Mit der normalen C-Nomenklatur würde man schreiben:

nav.navigationBarHidden = TRUE;

Es geht aber auch in der Info.plist... Einfach folgende Schlüssel hinzufügen

Einzutragen in Info.plist

Ladebildschirm anzeigen...

Im Bundle muss eine PNG-Datei namens "Default.png" existieren. Sie muss die Größe 320x480 mit 160dpi haben

...und anschließend den Hauptschirm einblenden lassen

Im folgenden Beispiel habe ich einen UIImageView namens contentView mit diversen Elementen gespickt. Mit setAlpha:0.0 mache ich ihn unsichtbar, bevor ich ihn dem View des Programms zuweise. Nach dem Aufruf commitAnimations wird der UIView von Alpha = 0.0 (unsichtbar) auf Alpha = 1.0 (sichtbar) eingeblendet.

[contentView setAlpha:0.0];
self.view = contentView;
[contentView release];
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:0.75];
[self.view setAlpha:1.0];
[UIView commitAnimations];

Einen kurzen Systemsound spielen

iPhone und iPod bieten die Möglichkeit, kurze Sounds abzuspielen. Das betrifft jedoch nur unkomprimiertes Audio im .wav oder .caf-Format. Nachteile: nur Mono, kein Looping, maximal ca. 4 Sekunden empfohlen. Trotzdem ist es nützlich, weil recht einfach zu programmiere, hier wird test.wav abgespielt, das im Bundle enthalten sein muss.

#include "AudioToolbox/AudioServices.h"
SystemSoundID = 1;
id sndpath = [[NSBundle mainBundle] pathForResource:@"test" ofType:@"wav"];
CFURLRef baseURL = (CFURLRef)[[NSURL alloc] initFileURLWithPath:sndpath];
AudioServicesCreateSystemSoundID(baseURL, &SystemSoundID);
// und hier abspielen
AudioServicesPlaySystemSound(SystemSoundID);

Um anschließend die geladenen Dateien wieder freizugeben, muss Folgendes getan werden

AudioServicesDisposeSystemSoundID(SystemSoundID);

iPhone vibrieren lassen

Diese Funktion kann ich mangels iPhone nicht testen. Die Audiotoolbox muss importiert werden.

#import "AudioToolbox/AudioToolbox.h"

AudioServicesPlaySystemSound (kSystemSoundID_Vibrate);

iPhone- oder iPod-Safari mit einer URL aufrufen

NSURL *url = [ [ NSURL alloc ] initWithString: @"http://www.quadworks.de" ];
[[UIApplication sharedApplication] openURL:url];

Zufallszahlen generieren

In der Startroutine "- (void)viewDidLoad" einfügen:

srand(time(NULL));

Hiermit wird dann eine Zahl zwischen 0 und 3 generiert

(random() % 3)

Eine kurze Pause einlegen

In manchen Fällen muss eine kurze Pause eingelegt werden. Dazu gibt es "sleep". Folgendes verzögert die Ausführung des Programms um 2 Sekunden.

sleep(2);

Daten im iPod speichern und wieder abrufen

Das Sichern von Daten (z.B. Highscores) geht so:

NSUserDefaults *prefs = [NSUserDefaults standardUserDefaults]; // weist prefs die Standardeinstellungen zu
[prefs setObject:@"TextToSave" forKey:@"keyToLookupString"]; // speichern von "TextToSave" in "keyToLookupString"
[prefs setInteger:42 forKey:@"integerKey"]; // speichern von 42 in "integerKey"
[prefs setDouble:3.1415 forKey:@"doubleKey"]; // speichern von 3.1415 als Real-Zahl in "doubleKey"
[prefs setFloat:1.2345678 forKey:@"floatKey"]; // speichern von 1.2345678 als Fließkommazahl in "floatKey"
[prefs synchronize]; // synchronisiert die Einstellungen

Der Abruf der Variablen und Inhalte läuft dann so:

NSUserDefaults *prefs = [NSUserDefaults standardUserDefaults];
NSString *myString = [prefs stringForKey:@"keyToLookupString"];
NSInteger myInt = [prefs integerForKey:@"integerKey"];
float myFloat = [prefs floatForKey:@"floatKey"];

Zuweisen von Variablen mit Typecasting

double meineDouble = [textfeld.text doubleValue]; // konvertiert den abgerufenen Text direkt in ein Double

Umwandeln von NSString in ein NSInteger

[NSString intValue]

Eingebettete PNG-Datei rotieren

Ein Bild (blatt.png, 100x100 Pixel Größe) an Position 35/35 setzen und um 1.55/PI rotieren. Das Framework CoreGraphics.framework muss eingebunden sein!

UIImageView *blatt;
blatt = [[UIImageView alloc] initWithFrame:CGRectMake(35.0f,35.0f,100.0f,100.0f)];
[blatt setImage:[UIImage imageNamed:@"blatt.png"]];
blatt.transform = CGAffineTransformMakeRotation(1.55); // in Rad
[contentView addSubview:(blatt)];

Zwei Zeichenketten verknüpfen

So kann man zwei Zeichenketten (NSStrings) verknüpfen. Dabei wird string2 an string1 angehängt.

NSString *string1 = @”Alpha”;
NSString *string2 = @”Beta”;
string1 = [string1 stringByAppendingString:string2];

Bundlenamen aus dem Bundle abrufen

ACHTUNG! Nach einigem Stress wegen fehlerhafter Darstellung fiel mir das Folgende auf: alle (!) lokalisierten Dateien müssen mit der Codierung UTF-16 erstellt werden. In xCode kann die Datei auch konvertiert werden.

[[[NSBundle mainBundle] localizedInfoDictionary] objectForKey:@"CFBundleDisplayName"]

Dies kann in der Datei InfoPlist.strings hinterlegt werden. Dazu wird für jede Sprache ein Unterordner, z.B. de.lproj erstellt. Über File/New File/Other=>Strings File wird anschließend die Datei InfoPlist.strings in de.lproj erstellt. Für jede andere Sprache geschieht das Gleiche. In diese Dateien wird jeweils

CFBundleDisplayName = "Mein Programm";

in der jeweiligen Sprache geschrieben. Über obigen Befehl wird dann der Bundle-Name abgerufen.

Programm lokalisieren

ACHTUNG! Auch hier gilt: Codierung UTF-16 benutzen!

Auf ähnliche Weise wie beim Bundlenamen kann ein Programm lokalisiert werden. Dazu über File/New File/Other=>Strings File eine Datei namens Localizable.strings in den Sprachordnern erstellen. Hier können einzelne Konstanten hinterlegt werden, die dann wie folgt abgerufen werden können:

NSLocalizedString(@"MeinWert", @"");

NIB bei Programmstart laden

Wer mit dem Interface Builder arbeitet, kann ein NIB relativ unkompliziert laden...

if (![NSBundle loadNibNamed:@"dasnibfile" owner:self]) {
// hat nicht geklappt
return;
}
// hat geklappt, weiter gehts

Pfad erstellen

Einen Pfad zu erstellen ist relativ einfach. Folgendes erstellt eine Referenz auf die Datei 1.wav.

CFURLRef baseURL = (CFURLRef)[[NSURL alloc] initFileURLWithPath:[[NSBundle mainBundle] pathForResource:@"1" ofType:@"wav"]];

Eine Referenz auf einen Unterordner "/de/test" erstellt man so:

CFURLRef baseURL = (CFURLRef)[[NSURL alloc] initFileURLWithPath:[[NSBundle mainBundle] pathForResource:@"1" ofType:@"wav" inDirectory:@"./de/test"]];

Der Ordner wird erstellt, wenn man den Ordner (nicht die einzelne Datei) auf xCode zieht. Dabei wird gefragt, ob Gruppen oder eine Folder Reference erstellt werden soll. Letzteres bewirkt, dass obiges inDirectory endlich Sinn macht.

Array: erstellen und zugreifen

Diese Zeilen erstellen ein Array aus NSStrings. Auf eines der Elemente wird dann zugegriffen.

NSArray *dasArray = [NSArray arrayWithObjects:@"eins", @"zwei", @"drei", nil];
NSLog([dasArray objectAtIndex:2]);
// sollte drei ins Log-Fenster schreiben

Eine Datei einladen

Hiermit wird eine Textdatei aus dem Applikation-Bundle eingelesen.

NSString *pfad = [[NSBundle mainBundle] pathForResource:@"meineDatei" ofType:@"txt"];
NSData *meineDaten = [NSData dataWithContentsOfFile:pfad];
if (meineDaten) {
// was Tolles damit anfangen.
}

Und hiermit wird eine Datei in einen Webview eingelesen, wenn die Datei nicht existiert, wird die quadWorks-Webseite aufgerufen.

NSString *pfad = [[NSBundle mainBundle] pathForResource:@"hilfe" ofType:@"htm"];
NSData *htmlData = [NSData dataWithContentsOfFile:pfad];
if (htmlData) {
[webView loadData:htmlData MIMEType:@"text/html" textEncodingName:@"UTF-8" baseURL:[NSURL URLWithString:@"http://www.quadworks.de"]];
}

Und schließlich das Einlesen einer Datei in einen String.

NSString *pfad = [[NSBundle mainBundle] pathForResource:@"wichtig" ofType:@"txt"];
if (pfad) {
NSString *meintext = [NSString stringWithContentsOfFile:pfad];
if (meintext) {
textView.text=meintext;
}
}

Das Dokumenten-Verzeichnis ermitteln

Wie kann man das Documents-Verzeichnis des angemeldeten Benutzers ermitteln?

- (NSString *)getDocumentsDirectory {
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
return [paths objectAtIndex:0];
}

Ermitteln, ob eine Datei existiert

Diese Funktion nebst entsprechendem Aufruf hilft dabei...

-(BOOL) isfile:(NSString *) path
{
const char *mypath = [path UTF8String];
FILE *testfile = fopen(mypath, "r");
if (testfile) { fclose(testfile); return YES; } else { return NO; }
}

Prüfen, ob es eine Datei "1.mp3" im Ordner "Musik" des App-Bundles gibt.

NSString *path = [[NSBundle mainBundle] pathForResource:@"1" ofType:@"mp3" inDirectory:@"musik/"];
if ([self isfile:(path)] == YES) { NSLog(@"jo"); } else { NSLog(@"nein"); }

Einen View wieder vom Superview entfernen

Manchmal muss ein Subview wieder entfernt werden... So gehts

// einen View einrichten und mit dem Tag 99 versehen. Am Besten ist die Nutzung
// von Konstanten, z.B. von 1000 bis 1050, um Subviews mit Tags zu versehen
UIImageView * meinView = [UIImageView alloc];
[meinView setTag:199];
[self.view meinView];
// wieder entfernen
[[self.view viewWithTag:99] removeFromSuperview];

Einen Timer verwenden

Periodische Aufrufe von Funktionen werden am Besten mit einem Timer realisiert. Im Beispiel wird alle 0,75s die Methode myTimerFireMethod aufgerufen, und zwar so lange, bis der Timer gestoppt wird.

NSTimer *myTimer;
myTimer = [NSTimer scheduledTimerWithTimeInterval:0.75 target:self
selector:@selector(myTimerFireMethod:) userInfo:nil repeats:YES];

Dazu benötigt man eine Function namens myTimerFireMethod, die periodisch aufgerufen werden soll. Der Name kann frei vergeben werden, jedoch muss die Prozedur identisch zu unten deklariert werden.

-(void) myTimerFireMethod:(NSTimer*)theTimer {
//tu' dies oder das...
}

Stoppen kann man den Timer schließlich mit dem Aufruf zu Invalidierung. Anschließend kann er "released" werden.

[myTimer invalidate];

Ein UI-Objekt spiegeln

Mit folgendem Befehl kann der entsprechende View gespiegelt werden. Das sollte auch mit anderen Objekten funktionieren (nicht ausprobiert).

view.transform = CGAffineTransformMakeScale(-1, 1);

gestapelte CALayer für Klicken unempfindlich machen

UI, die mittels gestapelter CALayer aufgebaut sind, können für Touch-Events unsichtbar gemacht werden. Dazu zur entsprechenden Klasse Folgendes hinzufügen.

- (BOOL)containsPoint:(CGPoint)p { return FALSE; }

Anzahl der Finger auf dem Display

Dies funktioniert mit einem UIView und einem UIViewController... Der Controller muss für Multitouch vorbereitet sein:

[meinView setMultipleTouchEnabled:YES];

Anschließend wird TouchesBegan aufgerufen, wenn das Display berührt wird:

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
// Dein Code...
}

Die Anzahl der Finger ermittelt das Folgende (in touchesBegan einfügen):

NSSet *touch = [event allTouches];
int nb = [touch count]; // enthält jetzt die Anzahl der Finger

Die Anzahl der Taps kann so ermittelt werden:

NSSet *touches [event allTouches];
int nb = [touches tapCount]; // enthält jetzt die Anzahl der Taps

Char (0-terminierter String) in NSString umwandeln

NSString * temp = [NSString stringWithCString:charstring]);

iPhone-Schlafmangel

Mit dieser Code-Zeile wird das Dimmen des Bildschirm und das anschließende Einschlafen unterbunden. Achtung! Frisst Batterie...

[UIApplication sharedApplication].idleTimerDisabled = YES;

Das Heimverzeichnis des Benutzers ermitteln

Um auf die eigenen Dokumente zugreifen zu können, oder dort Dateien abzulegen...

NSString * docs = [NSHomeDirectory() stringByAppendingPathComponent:@"Documents"];

Trackback-Link...

Objective-C fürs iPhone (10.09.09):
http://www.quadworks.de/?artikel=2009-02-18/23-02-52

Linke uns: Digg Delicious Google TwitThis Reddit StumbleUpon Mister Wong Yigg Oneview Folkd     Drucke uns: Druckvorschau öffnen

Weiterführendes

Kommentare

C-Programmierer schrieb am 20.03.2009

Super. Danke für den informativen Thread!

Objective C Programmierer schrieb am 01.08.2009 - 21:24:08

Von mir auch ein Danke für die gesammelten Informationen!

Wally schrieb am 28.08.2009 - 21:37:47

Vielen Dank hat mir sehr geholfen.

Kommentieren

Alle Felder müssen ausgefüllt sein!




Frühere Einträge iPod-Touch-Mikrofon Programme fürs iPhone und den iPod Spätere Einträge
nach oben erstellt mit microCMS, (c,p) 2008-2009 quadWorks IT-Services