Willkommen zu Teil 5 dieser Serie zu Objective-C. Heute betrachten wir die Speicherverwaltung, ein Element von Objective-C (und vielen anderen Sprachen), das neuere Programmierer zum Absturz bringen wird. Die meisten Skriptsprachen (wie z. B. PHP) erledigen das Speichermanagement automatisch, aber bei Objective-C müssen wir sorgfältig mit dem Speicher umgehen und manuell Speicherplatz für unsere Objekte erstellen und freigeben.
Es ist empfehlenswert, den von Ihrer Anwendung verwendeten Speicher im Auge zu behalten, damit keine Lecks auftreten oder der Speicher im System belastet wird. Noch wichtiger ist dies bei mobilen Systemen wie dem iPhone, wo der Speicher viel geringer ist als auf einem Desktop-Computer.
In Objective-C gibt es zwei Methoden zum Verwalten des Speichers: Die erste Referenzzähler und die zweite ist die Garbage Collection. Sie können sich diese als manuell und automatisch vorstellen, da vom Programmierer Referenzzähler hinzugefügt wird und die Garbage Collection das System ist, das unseren Speicher automatisch verwaltet. Ein wichtiger Hinweis ist, dass die Müllsammlung auf dem iPhone nicht funktioniert, weshalb wir nicht darauf achten, wie es funktioniert. Wenn Sie für den Mac programmieren möchten, sollten Sie sich die Dokumentation von Apple ansehen, um zu erfahren, wie die Speicherbereinigung funktioniert.
Wie verwalten wir unser Gedächtnis in unseren Apps? Erstens: Wann verwenden wir Speicher in unserem Code? Wenn Sie eine Instanz einer Klasse (eines Objekts) erstellen, wird Speicher zugewiesen, und unser Objekt kann jetzt ordnungsgemäß funktionieren. Ein kleines Objekt scheint jetzt nicht besonders gut zu sein, aber wenn Ihre Apps an Größe zunehmen, wird dies schnell zu einem enormen Problem.
Schauen wir uns ein Beispiel an, wir haben eine Art Zeichnungs-App und jede Form, die der Benutzer zeichnet, ist ein separates Objekt. Wenn der Benutzer 100 Formen gezeichnet hat, befinden sich 100 Objekte im Speicher. Nehmen wir an, der Benutzer beginnt von vorne, löscht den Bildschirm und zeichnet dann weitere 100 Objekte. Wenn wir unser Gedächtnis nicht richtig verwalten, werden am Ende 200 Objekte nichts anderes tun, als Speicher zu belasten.
Dem begegnen wir durch Referenzzählung. Wenn wir ein neues Objekt erstellen und allocation verwenden, haben unsere Objekte eine Zurückbehaltungszählung von 1. Wenn wir für dieses Objekt "keep" aufrufen, ist die Zurückhaltungszählung jetzt 2 und so weiter. Wenn wir das Objekt freigeben, verringert sich der Retain-Count auf 1. Während der Retain-Count nicht Null ist, bleibt unser Objekt in der Nähe, aber wenn der Keep-Count-Wert Null erreicht, hebt das System unser Objekt auf, wodurch der Speicher freigegeben wird.
Sie können verschiedene Methoden aufrufen, die sich auf die Speicherverwaltung auswirken. Wenn Sie ein Objekt unter Verwendung eines Methodennamens erstellen, der Allocation, New oder Copy enthält, übernehmen Sie zunächst den Besitz dieses Objekts. Dies gilt auch, wenn Sie die Retain-Methode für ein Objekt verwenden. Sobald Sie ein Objekt freigeben oder erneut freigeben (mehr dazu später), übernehmen Sie nicht mehr den Besitz dieses Objekts oder kümmern sich nicht darum, was mit dem Objekt geschieht.
Wenn wir also ein Objekt so vergeben,
myCarClass * car = [myCarClass-Zuordnung];
Wir sind jetzt für das Objekt Auto verantwortlich und müssen es später manuell freigeben (oder automatisch freigeben). Es ist wichtig zu beachten, dass die Anwendung abstürzen würde, wenn Sie versuchen, ein Objekt manuell freizugeben, das für die automatische Freigabe festgelegt wurde.
Da wir unser Objekt mithilfe von Allocation erstellt haben, hat unser Auto-Objekt jetzt eine Zurückbehaltungsanzahl von 1, dh es wird nicht freigegeben. Wenn wir unseren Gegenstand auch so behalten sollten;
[Auto behalten];
Dann ist unsere Zurückhaltezählung jetzt 2. Um das Objekt loszuwerden, müssen wir zweimal freigeben, um die Zurückhaltezählung auf 0 zu setzen. Da die Zurückhaltezählung jetzt Null ist, wird das Objekt freigegeben.
Wenn Sie ein neues XCode-Projekt erstellt haben, haben Sie möglicherweise einen Code bemerkt, der standardmäßig angezeigt wird und einen Autorelease-Pool erstellt. Bisher haben Sie ihn ignoriert. Jetzt werden wir sehen, was er tut und wo er verwendet werden soll.
Der Code, den Sie wahrscheinlich bereits kennen, sollte so aussehen.
NSAutoreleasePool * pool = [[NSAutoreleasePool-Zuordnung] init]; [pool drain];
Hinweis: Wenn Sie sich auf ältere Dokumentation beziehen, wird die letzte Zeile möglicherweise als release und nicht als drain angezeigt. Dies ist eine neuere Ergänzung der Sprache, tut aber im Wesentlichen dasselbe.
Inzwischen sollten Sie in der Lage sein, bis zu einem gewissen Grad zu sagen, was der obige Code tut. Es erstellt eine Instanz von NSAutoReleasePool namens pool, reserviert Speicher für diesen und initiiert ihn mit der init-Methode.
Wenn wir die Autorelease-Nachricht an ein Objekt senden, wird dieses Objekt dem Pool mit den meisten automatischen Freigaben hinzugefügt (Inner-Most, da Pools ineinander verschachtelt werden können - dazu später mehr). Wenn der Pool die Drain-Nachricht gesendet hat, werden alle Objekte, die die Autorelease-Nachricht gesendet haben, freigegeben. Die Autorelease verzögert im Wesentlichen die Freigabe bis später.
Dies ist nützlich, da viele Methoden, die ein Objekt zurückgeben, in der Regel ein automatisch freigegebenes Objekt zurückgeben. Das bedeutet, dass wir uns nicht um die Anzahl der beibehaltenen Objekte kümmern müssen, die wir gerade erhalten haben, und auch nicht, wie es sein wird später gemacht.
Ich habe vorhin kurz über die Möglichkeit gesprochen, autoreleased Pools zu verschachteln, aber was nützt uns das? Obwohl es mehrere Verwendungen gibt, besteht die häufigste Verwendung darin, einen Autorelease-Pool in einer Schleife zu verschachteln, die temporäre Objekte verwendet.
Wenn Sie beispielsweise über eine Schleife verfügen, die zwei temporäre Objekte erstellt, um zu tun, was immer Sie möchten, wenn Sie diese beiden Objekte für die automatische Freigabe festlegen, können Sie sie verwenden, bis der Pool die Drain-Nachricht gesendet hat, und Sie müssen sich nicht um das manuelle Freigeben kümmern freigeben Apple hat ein hervorragendes Beispiel dafür, wann Sie diese Art von verschachtelten Autorelease-Pools in der Dokumentation verwenden.
void main () NSAutoreleasePool * pool = [[NSAutoreleasePool Allocation] init]; NSArray * args = [[NSProcessInfo processInfo] -Argumente]; for (NSString * fileName in args) NSAutoreleasePool * loopPool = [[NSAutoreleasePool Allocation] init]; NSError * error = nil; NSString * fileContents = [[[NSString-Zuordnung] initWithContentsOfFile: Dateiname Kodierung: NSUTF8StringEncoding-Fehler: & Fehler] Autorelease]; / * Verarbeite den String, um weitere Objekte zu erstellen und erneut freizugeben. * / [loopPool drain]; / * Führen Sie die erforderlichen Aufräumarbeiten durch. * / [Poolablauf]; exit (EXIT_SUCCESS);
Quelle: mmAutoreleasePools
Das obige Beispiel hat etwas mehr als wir brauchen, aber die Struktur ist da. Wie Sie sehen, wird beim Öffnen der Anwendung und beim Laden von main ein Autorelease-Pool namens Pool erstellt. Bedeutet, dass etwas automatisch freigegeben wurde, bevor der Pool gesendet wird, wird die Drain-Nachricht diesem Autorelease-Pool zugewiesen, es sei denn, er befindet sich innerhalb eines Autorelease-Pools innerhalb dieses Pools (sorry, wenn sich das etwas verwirrend anhört).
Innerhalb der Schleife wird ein weiterer Autorelease-Pool mit dem Namen loopPool erstellt. Dieser Pool wird innerhalb der Schleife entleert, sodass alle in der Schleife freigegebenen Freigaben freigegeben werden, bevor die Schleife wiederholt wird (oder endet)..
Der innere Autorelease-Pool hat absolut keine Auswirkungen auf den äußeren Autorelease-Pool. Sie können beliebig viele Autorelease-Pools verschachteln. Wenn wir die Autorelease in der obigen Schleife verwendet haben, aber keinen separaten Autorelease-Pool hatten, werden alle Objekte, die wir erstellen, erst am Ende von main freigegeben. Wenn die Schleife also 100 Mal ausgeführt wurde, hätten wir 100 Objekte, die Speicher freigeben, die noch nicht freigegeben werden müssen - und damit unsere Anwendung aufblähen.
Lassen Sie uns vor dem Abschluss etwas betrachten, das die Speicherverwaltung zu einem leicht zu schluckenden Kapitel macht. Nachdem wir Objekte erstellt haben, haben wir uns daran erinnert, wie viele Referenzen ein Objekt hat und so weiter - aber wir haben noch nie eine tatsächliche Anzahl gesehen. Zu Bildungszwecken gibt es eine Methode, mit der wir ermitteln können, wie viele Verweise ein Objekt auf "holdCount "gesetzt hat. Die Art und Weise, in der wir ein keepCount für ein Objekt drucken, ist so:
NSLog (@ "keepCount für Auto:% d", [Autozurückhaltung]);
preservCount gibt eine ganze Zahl zurück, daher verwenden wir% d, um sie in der Konsole anzuzeigen. Es gibt seltene Fälle (auf die wir nicht eingehen werden), bei denen sich keepCount als falsch erweisen kann und daher nicht zu 100% auf das Programm zurückgegriffen werden sollte. Es ist nur für das Debugging implementiert. Daher sollte eine App niemals mit der keepCount-Methode live geschaltet werden.
Speichermanagement ist ein Thema, das für viele neue Programmierer schwierig ist, insbesondere für Programmierer, die aus Sprachen stammen, die sich um alles kümmern. Wir haben die Grundlagen besprochen, die ausreichen sollten, damit Sie Ihre Füße finden und die Speicherverwaltung in Ihre Apps integrieren können.
Apple verfügt über eine fantastische Entwicklerdokumentationsbibliothek auf seiner Entwickler-Website. Ich empfehle Ihnen dringend, herauszufinden, ob Sie nicht wissen, was uns heute anspricht. Wir haben uns bemüht, das Tutorial heute kurz und laserorientiert zu halten, um Ihnen das Verständnis der Speicherverwaltung ohne weitere Flusen zu erleichtern.
Fragen sind wie immer willkommen.
Experimentieren Sie einfach mit der Konsole, indem Sie ein einfaches Objekt erstellen, das einige synthetisierte Variablen enthält. Erstellen Sie einige Instanzen dieser Klasse und überprüfen Sie dann die Anzahl der beibehaltenen Werte mithilfe der Methode keepCount. Das beste Verständnis für das Speichermanagement ist das Starten von XCode und das Herumspielen mit Zuweisungen und Zurückbehalten usw. Beachten Sie, dass Abstürze und Fehler keine Ziegelmauer sind, da sie letztendlich dazu beitragen, Fehler in der Zukunft zu vermeiden.
In der nächsten Ausgabe werden wir uns Kategorien anschauen, eine großartige Funktion, die in Objective-C verfügbar ist und Entwickler viel Zeit sparen und für vereinfachten Code sorgen kann.