Ich habe versucht, eine existierende Methode von ViewController.m
von AppDelegate.m
in der Methode applicationDidEnterBackground
aufzurufen, also habe ich diesen Link gefunden: Aufruf der UIViewController-Methode vom App-Delegaten , die mir die Implementierung dieses Codes befahl:
In meinem ViewController.m
%Vor%In meinem AppDelegate:
%Vor%Und in der AppDelegate-Implementierung:
%Vor% Also habe ich diesen Code in mein Projekt eingefügt und es hat gut funktioniert, aber ich habe nicht verstanden, wie der Code Zeile für Zeile funktioniert. Was macht die sharedApplication
? Warum muss ich einen Delegaten setzen, anstatt nur eine Instanz von ViewController zu erstellen, wie zum Beispiel:
Hintergrundinformationen (Klassendefinition gegen Klasseninstanz)
Das wichtige Konzept ist hier der Unterschied zwischen einer Klassendefinition und einer Klasseninstanz.
Die Klassendefinition ist der Quellcode für die Klasse. Zum Beispiel enthält ViewController.m
die Definition für die Klasse myViewController
und AppDelegate.m
enthält die Definition für die Klasse AppDelegate
. Die andere in Ihrer Frage erwähnte Klasse ist UIApplication
. Das ist eine systemdefinierte Klasse, d. H. Sie haben keinen Quellcode für diese Klasse.
Eine Klasseninstanz ist ein Stück Speicher im Heap und ein Zeiger auf diesen Speicher. Eine Klasseninstanz wird normalerweise mit einer Codezeile wie dieser erstellt.
%Vor% Beachten Sie, dass alloc
Speicherplatz auf dem Heap für die Klasse reserviert und dann init
die Anfangswerte für die Variablen / Eigenschaften der Klasse festlegt. Ein Zeiger auf die Instanz wird dann in foo
gespeichert.
Wenn Ihre Anwendung startet, tritt die folgende Sequenz von Ereignissen auf (grob gesprochen):
delegate
in der UIApplication-Instanz Die Speicherung des Zeigers auf MyViewController ist, wo Dinge unordentlich werden. Die AppDelegate-Klasse verfügt über eine UIWindow-Eigenschaft namens window
. (Sie können dies in AppDelegate.h sehen.) Wenn die App nur über einen Ansichtscontroller verfügt, wird der Zeiger auf diesen Ansichtscontroller in der window.rootViewController
-Eigenschaft gespeichert. Aber wenn die App mehrere View-Controller hat (unter einem UINavigationController oder einem UITabBarController), werden die Dinge kompliziert.
Die Spaghetti-Code-Lösung
Das Problem, auf das Sie stoßen, ist folgendes: Wenn das System die Methode applicationDidEnterBackground
aufruft, wie erhalten Sie den Zeiger auf den View-Controller? Nun, technisch gesehen hat der App-Delegate einen Zeiger auf den View-Controller irgendwo unter der window
-Eigenschaft, aber es gibt keine einfache Möglichkeit, diesen Zeiger zu erhalten (vorausgesetzt, die App hat mehr als einen View-Controller).
Der andere Thread schlug einen Spaghettikode-Ansatz für das Problem vor. (Beachten Sie, dass der Spaghetti-Code-Ansatz nur vorgeschlagen wurde, weil das OP in diesem anderen Thread die Dinge nicht korrekt mit Benachrichtigungen erledigen wollte.) So funktioniert der Spaghetti-Code
%Vor% Dieser Code ruft den Zeiger auf die vom System erstellte UIApplication-Instanz ab und fragt dann die Eigenschaft delegate
ab, um einen Zeiger auf die AppDelegate-Instanz abzurufen. Der Zeiger auf self
, der ein Zeiger auf die MyViewController-Instanz ist, wird dann in einer Eigenschaft in AppDelegate gespeichert.
Der Zeiger auf die MyViewController-Instanz kann dann verwendet werden, wenn das System applicationDidEnterBackground
aufruft.
Die richtige Lösung
Die richtige Lösung ist die Verwendung von Benachrichtigungen (wie in kkumpavats Antwort)
%Vor% Mit Benachrichtigungen speichern Sie keine überflüssigen Zeiger auf Ihre View-Controller, und Sie müssen nicht herausfinden, wo das System den Zeiger auf Ihren View-Controller gespeichert hat. Wenn Sie addObserver
für UIApplicationDidEnterBackgroundNotification
aufrufen, weisen Sie das System an, die Methode didEnterBackground
des View-Controllers direkt aufzurufen.
Sie haben zwei Fragen hier.
1) Was macht die sharedApplication
?
Die [UIApplication sharedApplication]
gibt Ihnen die UIApplication-Instanz gehört zu Ihrer Anwendung. Dies ist der zentrale Kontrollpunkt für Ihre App. Weitere Informationen finden Sie UIApplication-Klassenreferenz auf iOS-Entwicklern Website.
2) Warum muss ich einen Delegaten setzen, anstatt nur eine Instanz von ViewController zu erstellen?
Wenn Sie den Controller in AppDelegate
erneut mit alloc
/ init
erstellen, wird eine neue Instanz erstellt, und diese neue Instanz zeigt nicht auf den Controller, auf den Sie verweisen. So erhalten Sie nicht das Ergebnis, das Sie suchen.
In diesem speziellen Anwendungsfall von applicationDidEnterBackground
benötigen Sie jedoch keine Referenz Ihres Controllers in AppDelegate
. Ihr ViewController kann sich für UIApplicationDidEnterBackgroundNotification
notification in viewDidLoad
function registrieren und in dealloc
function die Registrierung aufheben.
Der View-Controller ist bereits als Teil des NIB- / Storyboard-Prozesses instanziiert. Wenn also Ihr App-Delegat sein eigenes alloc
/ init
erstellt, erstellen Sie einfach eine weitere Instanz (die keine Beziehung zu der erstellten erstellt) NIB / Storyboard).
Der Zweck des Konstrukts, das Sie skizzieren, besteht lediglich darin, dem App-Delegierten einen Verweis auf den View-Controller zu geben, den das NIB / Storyboard für Sie instanziiert hat.
Tags und Links objective-c iphone ios uiviewcontroller appdelegate