• Apfeltalk ändert einen Teil seiner Allgemeinen Geschäftsbedingungen (AGB), das Löschen von Useraccounts betreffend.
    Näheres könnt Ihr hier nachlesen: AGB-Änderung
  • Viele hassen ihn, manche schwören auf ihn, wir aber möchten unbedingt sehen, welche Bilder Ihr vor Eurem geistigen Auge bzw. vor der Linse Eures iPhone oder iPad sehen könnt, wenn Ihr dieses Wort hört oder lest. Macht mit und beteiligt Euch an unserem Frühjahrsputz ---> Klick

Memorymanagement Problem

Termy

Boskop
Registriert
28.12.09
Beiträge
209
Hey,

Ich schreibe gerade Tetris für iPhone und habe da ein Problem und zwar in meiner Medthode -(void)viewDidLoad{} rufe ich mehrere Medhoden auf. Beim Aufruf der dritten Methode spuckt er einen Error raus: "EXC_BAD_ACCESS". Ich vermute, dass dies mit dem Memorymanagement zusammenhängt. Hier ist meine Medhode:
Code:
- (void)viewDidLoad {
	[super viewDidLoad];
	drawImage = [[UIImageView alloc] initWithImage:nil];
	drawImage.frame = self.view.frame;
	[self.view addSubview:drawImage];
    
	Klotzgroesse = 480/20 -1;
	
	int x, y;
	
	for (x = 0; x <= 13; x = x + 1) {
		for (y = 0; y <= 21; y = y + 1) {
			Spielfeld[x][y].X = (x - 1) * Klotzgroesse + (x - 1)+2;
			Spielfeld[x][y].Y = (y - 1) * Klotzgroesse + (y - 1)+2;
			Spielfeld[x][y].Leer = true;
			Spielfeld[x][y].NrX = x;
			Spielfeld[x][y].NrY = y;
		}
	}
	
	[self ZeichneSpielfeld];
	NSLog(@"Spielfeld setted up");
	[self NeueForm];
	NSLog(@"Forms loaded");
	[self FormsLeermachen:0 Pruefen:0 XVerschiebung:0 YVerschiebung:0 KloetzeSetzen:0 RotationPruefen:nil ExtraForm:0 GhostMode:0];
	NSLog(@"First Form drawed");
	[self RechneGhostY];
	NSLog(@"Ghost calculatet(%i)", GhostY);
	[self FormsLeermachen:0 Pruefen:0 XVerschiebung:0 YVerschiebung:0 KloetzeSetzen:0 RotationPruefen:nil ExtraForm:0 GhostMode:1];
	NSLog(@"Ghost drawed");
	[NSTimer scheduledTimerWithTimeInterval:1.0f target:self selector:@selector(Timer) userInfo:nil repeats:YES];
	NSLog(@"Timer started");
}

Ich vermute auch, dass ich irgendwas hätte releasen bzw. retainen müssen aber das geht komischerweise nicht mit integer oder float Variablen.

Wäre echt nett wenn mir das nochmal jemand erklären könnte, warum genau das nicht funktioniert
 
Zuletzt bearbeitet:

Termy

Boskop
Registriert
28.12.09
Beiträge
209
Wäre wirklich nett wenn jemand helfen könnte! Ich gebe auch gerne mehr Infos wenn ihr die braucht
 

Termy

Boskop
Registriert
28.12.09
Beiträge
209
Versehentlich ist ein Großteil des Codes durch Herumprobieren und Kopieren verloren gegangen. Naja trotzdem danke ;)
 

LittlePixel

Strauwalds neue Goldparmäne
Registriert
09.07.08
Beiträge
641
Hallo,

bitte lies zunächst mal das offizielle Dokument: http://developer.apple.com/mac/library/documentation/cocoa/Conceptual/MemoryMgmt/MemoryMgmt.html

Ich vermute auch, dass ich irgendwas hätte releasen bzw. retainen müssen aber das geht komischerweise nicht mit integer oder float Variablen.
Puh, das hört sich alles nach raten an. Hast Du schon Grundlagen gelesen?
Ja, da hast Du recht, dass das so nicht geht. Aber was ist z.B. mit "drawImage"? Das ist doch ein Objekt, für das Du Speicher reservierst und nie mehr freigibst.

"Klotzgroesse" ist was? Scheinbar keine Klasse. Also bitte klein schreiben.
Des Weiteren solltest Du Dir dann das Thema Getter und Setter genau durchlesen.

"ZeichneSpielfeld" ist was? Scheinbar keine Klasse. Also bitte klein schreiben.
Was ist eine Methode? Lesen.

Das sind nur die Dinge, die ich mit einem Blick gesehen habe. Wird aber wahrscheinlich nicht mal das Problem sein.

Meine Empfehlung: Lesen, verinnerlichen und dann probieren.

Viele Grüße
 

meru

Winterbanana
Registriert
30.09.06
Beiträge
2.187
Habe zwar auch nicht so die Ahnung aber bist du dir sicher das bei dem timerIntervall "1.0f" stehen soll ?

mfg Meru

P.S aus meiner Erfahrung als Anfänger weis ich das man ein EXC_BAD_ACCESS auch anders erzeugen als mit einer falschen Speicherverwaltung (Schreibfehler und so)
 

Poljpocket

Salvatico di Campascio
Registriert
07.01.07
Beiträge
432
NSTimeInterval ist definitiv kein float, sondern double. Das kleine f hinter der floating number erzwingt nämlich eine Umwandlung von automatischem double in float. Nimm das wirklich raus, ist nicht gut.

Gruss ppocket

PS: Du hast ja schon ganz schön nach jedem Befehl ein Consolen-Output. Welches ist denn die letzte Ausgabe? Denn genau danach muss der Fehler passieren und somit kennst du die Zeile, in der der Fehler passiert. Ich mache das auch oft so, wenn ich keine Fehler finde :) Also sag uns mal, welche Ausgabe zuletzt steht, bevor das signal kommt.
 

Termy

Boskop
Registriert
28.12.09
Beiträge
209
okay ich wusste nicht, dass man methodennamen immer kleinschreibt ;)
Das f beim Timer aufruf nehme ich gleich mal raus. Als letzes steht übrigens "Forms loaded"in der Console.
Vielen Dank für die Tipps
Ich versuch das so mal und dann guck ich ob es geht. Kann aber was dauern, da mir Methoden untergegangen sind (keine komplizierten zum Glück)

Achso die Dokumentation habe ich auch vorher schon gelesen und auch verstanden. Die arbeiten dort aber immer mit Objekten, wenn sie etwas releasen oder retainen. Ich z.B. nicht.
 

Termy

Boskop
Registriert
28.12.09
Beiträge
209
OMG ich hab es rausgefunden:
Code:
extraForm3.Form = rand() % 6;
	float Farbe[3];
	switch (extraForm3.Form) {
		case 0: Farbe[1] = 0.5; Farbe[2] = 0.5; Farbe[3] = 1.0; break; //Hellblau
		case 1: Farbe[1] = 1.0; Farbe[2] = 0.5; Farbe[3] = 0.5; break; //Orange
		case 2: Farbe[1] = 0.0; Farbe[2] = 0.0; Farbe[3] = 1.0; break; //Dunkelblau
		case 3: Farbe[1] = 1.0; Farbe[2] = 0.0; Farbe[3] = 0.0; break; //Rot
		case 4: Farbe[1] = 0.0; Farbe[2] = 1.0; Farbe[3] = 0.0; break; //Gruen
		case 5: Farbe[1] = 0.5; Farbe[2] = 0.5; Farbe[3] = 0.5; break; //Gelb
 		case 6: Farbe[1] = 1.0; Farbe[2] = 0.0; Farbe[3] = 1.0; break; //Violett
	}
	extraForm3.Farbe[1] = Farbe[1];
	extraForm3.Farbe[2] = Farbe[2];
	extraForm3.Farbe[3] = Farbe[3];

Ich hab auf ne Arrayposition zugegriffen, die es gar nicht gibt. So ein dummer Schreibfehler.
Das ist die Methode - (void)neueForm{}. Komisch ist aber, dass er den NSLog(@"Forms loaded"); noch ausgegeben hat.

Achso und für die, die den Fehler nicht sehen:
float Farbe[3];
Ersetzen mit
float Farbe[4];
 

LittlePixel

Strauwalds neue Goldparmäne
Registriert
09.07.08
Beiträge
641
Hallo,

Achso die Dokumentation habe ich auch vorher schon gelesen und auch verstanden. Die arbeiten dort aber immer mit Objekten, wenn sie etwas releasen oder retainen. Ich z.B. nicht.
Natürlich hast Du Objekte. Vor allem mit einem großen Fehler, den ich Dir genannt habe.
Aber das hast Du scheinbar wegignoriert.

Achso die Dokumentation habe ich auch vorher schon gelesen und auch verstanden.
Glaube ich Dir nicht. Bitte lies es nochmals.

Ich versuch das so mal und dann guck ich ob es geht.
Gehen wird schnell was. Das ist nie das Problem.
Es ist aber noch viel mehr die Frage der Qualität ;)

Wenn Du die Hinweise ernst nimmst, dann wird es auch was :)

Viele Grüße
 

ifthenelse

Fießers Erstling
Registriert
07.12.06
Beiträge
129
Btw.

float Farbe[3];
Ersetzen mit
float Farbe[4];
Was steht denn dann bei Dir in Farbe[0]? Und warum weist Du dann hier doubles float-Variablen zu?

Ich würde mich an Deiner Stelle wirklich noch einmal mit der Doku beschäftigen. Für Farben z.B. stellt Cocoa (Touch) eine Klasse namens UIColor bereit. Zum Zeichnen wirst Du die eh brauchen. Wenn Du ein prozedurales einem objektorientiertem Paradigma aufzwingen willst, wirst Du irgendwann mal Schiffbruch erleiden...
 

Termy

Boskop
Registriert
28.12.09
Beiträge
209
In Farbe[0] steh nichts. Ich habe mich da zuerst vertan.

Habe mir die Dokumentation erneut durchgelesen. Verstehe zwar nicht allzu viel aber ich hoffe es bringt was.

"Wenn Du ein prozedurales einem objektorientiertem Paradigma aufzwingen willst, wirst Du irgendwann mal Schiffbruch erleiden." Wie meinst du das?

Naja im Moment ist auf jeden Fall ein neues Problem aufgetaucht und zwar braucht mein App zu viel Arbeitsspeicher. Schon nach 10 Sekunden hab ich 2 Memory Warnungen und die App stürzt ab. Ich habe wahrscheinlich zu viele Variablen, die ich nicht release. Wenn ich aber Versuche NSInteger oder float Variablen zu releasen, dann funktioniert das nicht. Woran kann das liegen?
Hier ein Beispiel:
NSString *myString = [[NSString alloc] initWithFormat:mad:"%i", meinInteger];
//myString benutzen
[myString release];
Funktioniert.

NSInteger myInteger = [[NSInteger alloc] init];
myInteger = 5;
//myInteger benutzen
[myInteger release];
Funktioniert nicht.
 
Zuletzt bearbeitet:

MacApple

Schöner von Bath
Registriert
05.01.04
Beiträge
3.652
Das könnte daran liegen, das [tt]NSInteger[/tt] keine Klasse ist. ;)

MacApple
 

ifthenelse

Fießers Erstling
Registriert
07.12.06
Beiträge
129
...Funktioniert nicht.

Natürlich nicht. NSInteger und float sind elementar, keine Klassen. Zum Speicherproblem hat Dir LittlePixel schon einen zielführenden Hinweis gegeben.

Eigentlich ist es gar nicht so schwer: Für jedes retain auf ein Objekt musst Du auch zu einem geeigneten Zeitpunkt ein release veranlassen. Die Schwierigkeit besteht darin, a) diesen Zeitpunkt zu (er)kennen und b) alle Varianten zu kennen, wo "retaint" und "releast" wird...

Außerdem ist die ressourcenschonende Programmierung für's iPhone extrem wichtig, man hat halt nicht so viel davon! Bei Images sollte man z.B. bevorzugt "png"s verwenden...

Gruss, Jörg
 

Termy

Boskop
Registriert
28.12.09
Beiträge
209
Das Problem ist, dass ich in meinem Programm keinen einzigen alloc, oder retain habe, weil ich nur NSInteger und float benutze. Demnach sehe ich auch nichts was ich releasen kann. Was kann ich denn da machen?

Wie gesagt bin Neuling in solch ressourcenschonender Programmierung, habe diese Probleme vorher nie gehabt.

Okay LittlePixel sagt, ich soll drawImage releasen. Im übrigen hab ich drawImage jetzt in den Interface Editor hinzugefügt, so kann ich auf eine lokale Deklaration verzichten. Wenn ich drawImage einmal release, dann funktioniert das auf jeden Fall. Ob mehr RAM frei wird weiß ich nicht. Wenn ich es erneut release (ohne es zu retainen) wird es logischerweise gelöscht. Genau das verursacht bei mir einen Crash, da ich die ganze Zeit drauf zeichne. Wird es etwas bringen es beim MemoryWarn erst zu retainen und dann zu releasen?
 

Termy

Boskop
Registriert
28.12.09
Beiträge
209
Ich glaube ich habe den Fehler gefunden. Jedesmal wenn eine neue Form eingeführt oder horizontal verschoben wird, dann wird geprüft wie tief sie noch fallen kann. In dieser Methode wird die Form solange pseudo-gezeichnet bis meine Zeichenroutine ausgibt, dass es nicht mehr geht. In dieser Zeichenroutine, die gleichzeitig die Prüf- als auch die Zeichenfunktion enthält wird ein GraphicsContext erstellt, der (weil er ja nur prüft) nicht mehr releast wird.

Als ich das verändert habe, habe ich es mal ein paar Minuten durchlaufen lassen und keinen MemoryWarn mehr bekommen. Ich werde das jetzt mit Instruments nachprüfen!

//Edit: Instruments hat keinerlei Memoryleaks gefunden!
 

Poljpocket

Salvatico di Campascio
Registriert
07.01.07
Beiträge
432
woah, und ist dein Programm dann noch effizient, wenn du immer alles zeichnest, bevor du es sozusagen dann zeichnest? (komische Wortwahl)
Denn der Prozessor und die Grafikkarte kann man auch als Ressourcen ansehen und auch da hats auf dem iPhone nicht allzuviel davon :p
Das müsste doch effizienter auch zu lösen sein... nur so als Anregung!

Gruss ppocket
 

Termy

Boskop
Registriert
28.12.09
Beiträge
209
Ja, aber das macht er nur wenn er die Form wechselt. Er muss ja wissen wo stop ist, damit die Form nicht aus dem Spielfeld wandert. Das könnte ich natürlich auch vor jedem Schritt abfragen. Dann bekomme ich aber nicht den Ghost gezeichnet, halbtransparent, der zeigen soll, wo der Stein landet. Guck dir mal das original Tetris aus dem Appstore an, dann weist du was ich meine!

Das iPhone schafft das von den Ressourcen her aber alles super, hätte ich nicht gedacht! Bin natürlich nicht der beste Programmierer (und auch neu in den Objektorientierten Sprachen), deswegen denke ich wird es mit Sicherheit auch eine "saubere" Lösung geben.
 

Poljpocket

Salvatico di Campascio
Registriert
07.01.07
Beiträge
432
achso, da wird Einiges klar. Ich empfehle dir aber wärmstens, die Zeichenroutine von der Ghost-Routine zu trennen. Du kannst zum Beispiel am Anfang den Pfad berechnen, speichern und dann auf dem Pfad die Anzeige animieren. Der Ghost zeichnest du dann am letzten Punkt des Pfades. Wenn sich die Situation ändert, berechnest du halt nen neuen Pfad. Aber ich würde das nicht mit dem View selbst tun, denn dieses soll nur zeichnen, nicht rechnen.

Ich schneide mit diesen Ausführungen das Konzept "Model-View-Controller" an, welches von den Cocoa/UIKit Klassen strikt durchgezoen wird. Ein gutes Beispiel dafür ist NSTableView. Dieses View benutzt eine dataSource, welche den Controller darstellt. Dieser Controller hat eine Referenz zu den angezeigten Daten und sagt dem TableView, wie es diese Daten anzeigen soll. Dabei sind die Rollen klar getrennt, das Model sind die Daten, welche das View nicht zwingend kennt. Der Controller ist - wie gesagt - die dataSource, welche "berechnet" und das View fragt über die dataSource-Methoden gezielt nur das ab, was es braucht. Das ist perfektes MVC!

Gruss ppocket

PS: Google-Suche über dieses Thema bringt dich weiter!
 

Termy

Boskop
Registriert
28.12.09
Beiträge
209
achso, da wird Einiges klar. Ich empfehle dir aber wärmstens, die Zeichenroutine von der Ghost-Routine zu trennen. Du kannst zum Beispiel am Anfang den Pfad berechnen, speichern und dann auf dem Pfad die Anzeige animieren. Der Ghost zeichnest du dann am letzten Punkt des Pfades. Wenn sich die Situation ändert, berechnest du halt nen neuen Pfad.

Ich konnte das nicht so gut erklären, aber so wie du meinst mache ich das auch! Mit Pseudo-zeichnen meinte ich nicht, dass sie gezeichnet und dann wieder gelöscht wird, sondern dass die Form nur guckt ob sie da, wo sie gezeichnet werden würde, auch wirklich hinpasst. Das wiederhole ich dann ein paar mal schon hab ich meinen "Pfad".

Aber ich würde das nicht mit dem View selbst tun, denn dieses soll nur zeichnen, nicht rechnen.

Du meinst also ich soll nur die reine Zeichenroutine in der View lassen und für alles andere eine eigene Klasse aufbauen?

Ich schneide mit diesen Ausführungen das Konzept "Model-View-Controller" an, welches von den Cocoa/UIKit Klassen strikt durchgezoen wird. Ein gutes Beispiel dafür ist NSTableView. Dieses View benutzt eine dataSource, welche den Controller darstellt. Dieser Controller hat eine Referenz zu den angezeigten Daten und sagt dem TableView, wie es diese Daten anzeigen soll. Dabei sind die Rollen klar getrennt, das Model sind die Daten, welche das View nicht zwingend kennt. Der Controller ist - wie gesagt - die dataSource, welche "berechnet" und das View fragt über die dataSource-Methoden gezielt nur das ab, was es braucht. Das ist perfektes MVC!

Okay, das muss ich mir mal angucken! Danke für deine Tipps ;)
 

Poljpocket

Salvatico di Campascio
Registriert
07.01.07
Beiträge
432
Wenn du MVC - stuff gelesen hast, glaube ich, dass sich diese Frage erübrigt :). Es ist am Einfachsten, bei den Überlegungen von Apple mitzumachen, denn so bekommt man das beste Resultat, weil ja alle Cocoa-Klassen mit MVC arbeiten.

Gruss ppocket