Comment obtenir une référence au délégué d'application dans Swift?

409

Comment obtenir une référence au délégué d'application dans Swift?

En fin de compte, je souhaite utiliser la référence pour accéder au contexte de l'objet géré.

AperioOculus
la source
8
Notez que certains considéreraient l'utilisation du délégué d'application comme conteneur pour le contexte d'objet géré ou d'autres objets «globaux» comme un anti-modèle. Pensez à demander au délégué de l'application de passer le MOC au contrôleur, plutôt que de le faire le trouver.
Kristopher Johnson
1
@KristopherJohnson Hey Kris, comment puis-je faciliter l'injection de dépendances AppDelegate dans les contrôleurs de vue? Instancier le contrôleur de vue par programme et utiliser la réflexion pour décider quoi instancier / injecter, récursivement? Y a-t-il des cadres qui peuvent aider à cela? Si je dois faire cela pour chaque contrôleur de vue manuellement, mon AppDelegate va être énorme! Oh, de préférence sans créer une usine pour tout :)
Jimbo
1
Une recherche rapide a trouvé Swinject qui a également un câblage automatique :)
Jimbo
6
Pour les programmeurs qui déconseillent de mettre quoi que ce soit d '"étranger" dans le délégué de l'application, c'est un peu absurde car la documentation Apple indique explicitement que l'un "crucial role"des UIApplicationDelegatesingleton est "...to store your app’s central data objects or any content that does not have an owning view controller." developer.apple.com/documentation/uikit/uiapplicationdelegate
bsod

Réponses:

757

L'autre solution est correcte dans la mesure où elle vous fournira une référence au délégué de l'application, mais cela ne vous permettra pas d'accéder aux méthodes ou variables ajoutées par votre sous-classe d'UIApplication, comme votre contexte d'objet géré. Pour résoudre ce problème, il vous suffit de passer à "AppDelegate" ou à ce que votre sous-classe UIApplication soit appelée. Dans Swift 3, 4 et 5 , cela se fait comme suit:

let appDelegate = UIApplication.shared.delegate as! AppDelegate
let aVariable = appDelegate.someVariable
Mick MacCallum
la source
10
Dans le cas où quelqu'un a toujours des problèmes, le ciblage d'OS X nécessite que vous importiez Cocoa pour que cela fonctionne pour NSApplication.sharedApplication (). Je suppose que iOS aurait besoin de l'équivalent.
smaurice
2
C'est la plus utile des deux réponses.
Joe
3
@zacjordaan En utilisant cette méthode, vous obtiendrez la saisie semi-automatique pour la propriété, mais cela ne fonctionnera pas réellement. De cette façon, vous créerez une nouvelle instance de la classe AppDelegate chaque fois que vous l'utiliserez. Il vaut mieux utiliser le délégué accessible via le singleton sharedApplication. Et en ce qui concerne votre deuxième question, oui, vous voulez probablement utiliser une constante. Même si vous modifiez peut-être les propriétés de AppDelegate, vous ne réaffecterez probablement pas le pointeur à autre chose, auquel cas, il n'y a pas besoin de variable. Cela dépend entièrement de vous. Faites ce qui convient à vos besoins.
Mick MacCallum
2
Un excellent conseil! J'avais pensé à tort que AppDelegate () était singleton mais après avoir réfléchi à ce que vous avez dit, je me suis rendu compte que si c'était le cas, il n'y aurait pas de modèle d'application partagée à utiliser de cette manière. Bien sûr, je ne veux pas engendrer d'instances inutiles si je n'ai pas à le faire, donc votre déclaration constante conviendra parfaitement; Je vous remercie.
zacjordaan
4
Je ne veux pas ajouter ceci comme réponse distincte, mais pour obtenir AppDelegate avec vos propres méthodes, propriétés dans le projet où un Swift et un Obj-c sont utilisés Vous devez ajouter #import "AppDelegate.h" à "ProjectName-BridgingHeader .h "
Marcin Mierzejewski
44

Swift 4.2

Dans Swift, facile d'accès dans vos VC

extension UIViewController {
    var appDelegate: AppDelegate {
    return UIApplication.shared.delegate as! AppDelegate
   }
}
DogCoffee
la source
26

Constructeurs de commodité

Ajouter dans AppDelegate Class à la fin du code

Swift 5

func appDelegate() -> AppDelegate {
    return UIApplication.shared.delegate as! AppDelegate
}

Pour utiliser la référence AppDelegate dans votre classe?


Appelez la méthode AppDelegate

appDelegate (). setRoot ()

AiOsN
la source
Ce serait bien d'expliquer ce que fait setRoot () et quand l'appeler. par exemple, est-il correct de l'appeler à partir d'un ViewController? D'un test unitaire où la fenêtre n'est pas encore définie? Plus de contexte serait formidable.
Houman
@Houman setRoot est une méthode d'AppDelegate qui pourrait être utilisée pour basculer entre plusieurs racines ou ParentViewController et pourrait être n'importe quelle méthode. La discussion porte sur la manière d'obtenir la référence d'AppDelegate pour un accès ultérieur, mais espérons que setRoot doit également être clair.
AiOsN
19

C'est à peu près la même chose que dans Objective-C

let del = UIApplication.sharedApplication().delegate
Connor
la source
19

Cela pourrait être utilisé pour OS X

let appDelegate = NSApplication.sharedApplication().delegate as AppDelegate
var managedObjectContext = appDelegate.managedObjectContext?
jiminybob99
la source
3
Ou tout simplementlet appDelegate = NSApp.delegate as AppDelegate
Vladimir Prudnikov
1
Dans Swift 3, utilisezlet appDelegate = NSApplication.shared().delegate as AppDelegate
Dirk
4
Dans Swift 4 :NSApp.delegate as? AppDelegate
Nick
12

Voici la version Swift 2.0:

let delegate = UIApplication.sharedApplication().delegate as? AppDelegate

Et pour accéder au contexte de l'objet géré:

    if let delegate = UIApplication.sharedApplication().delegate as? AppDelegate {

        let moc = delegate.managedObjectContext

        // your code here

    }

ou, en utilisant la garde:

    guard let delegate = UIApplication.sharedApplication().delegate as? AppDelegate  else {
        return
    }

    let moc = delegate.managedObjectContext

    // your code here
Paul Ardeleanu
la source
10

SWIFT <3

Créer une méthode dans AppDelegate Class pour ex

func sharedInstance() -> AppDelegate{
        return UIApplication.sharedApplication().delegate as! AppDelegate
    }

et l'appeler un peu ailleurs par ex

let appDelegate : AppDelegate = AppDelegate().sharedInstance()

SWIFT> = 3.0

func sharedInstance() -> AppDelegate{
    return UIApplication.shared.delegate as! AppDelegate
}
Dharmbir Singh
la source
2
cela fonctionne aussi, et j'aime l'idée de la dénomination sharedInstance. Merci!
John Griffiths
2
Votre exemple instancierait toujours un nouvel AppDelegateobjet chaque fois que vous AppDelegate().sharedInstance()
appelez
1
J'aime mieux cette solution que la solution acceptée (qui est verbeuse "sans vergogne" si vous devez l'utiliser partout). Je pensais à expérimenter avec extensionpour NSApplicationavant que je trouve cette réponse, mais cela est beaucoup mieux. De nos jours, vous voudrez probablement utiliser une propriété en lecture seule calculée par classe shared, peut-être souhaitez-vous publier une mise à jour pour Swift 3?
Patru
1
Je suis en train de refactoriser mon code à utiliser, static var shared : TournamentDelegate? { get { return NSApplication.shared().delegate as? TournamentDelegate } }ce qui est plus conforme au style Swift 3 en développement d'utiliser des propriétés en lecture seule calculées pour ce type de choses. Je pourrai probablement laisser tomber le ?une fois le refactoring terminé, vous ne pensez pas? (Désolé, le formatage du code dans les commentaires est toujours un gâchis.)
Patru
@ pxpgraphics UIApplication est une classe singleton donc pas besoin de s'inquiéter de l'instanciation multiple.
Abhijith
10

À part ce qui est dit ici, dans mon cas, j'ai raté l'importation d'UIKit:

import UIKit
Javier Calatrava Llavería
la source
6

Essayez simplement ceci:

Swift 4

// Call the method
(UIApplication.shared.delegate as? AppDelegate)?.whateverWillOccur()

où dans votre AppDelegate:

// MARK: - Whatever
func whateverWillOccur() {

    // Your code here.

}

la source
5

Voici une extension UIApplicationDelegatequi évite de coder en dur le AppDelegatenom de la classe:

extension UIApplicationDelegate {

    static var shared: Self {    
        return UIApplication.shared.delegate! as! Self
    }
}

// use like this:
let appDelegate = MyAppDelegate.shared // will be of type MyAppDelegate
nyg
la source
sur le Mac pour NSApplicationDelegatecela me donne: 'Self' is only available in a protocol or as the result of a method in a class; did you mean 'AppDelegate'?. Est-ce obsolète?
pkamb
@pkamb Je viens de l'essayer dans un nouveau projet et je n'ai pas cette erreur. J'ai remplacé UIApplicationDelegatepar NSApplicationDelegateet UIApplicationpar NSApplication.
nyg
5
  1. Assurez-vous import UIKit

  2. let appDelegate = UIApplication.sharedApplication().delegate! as! AppDelegate

Sachin Nikumbh
la source
4

c'est très simple

Instance de délégué d'application

let app = UIApplication.shared.delegate as! AppDelegate

vous pouvez appeler une méthode avec une seule syntaxe de ligne

app.callingMethod()

vous pouvez accéder à une variable avec ce code

app.yourVariable = "Assigning a value"
Harendra Tiwari
la source
2

Dans mon cas, je manquais import UIKitau sommet de ma NSManagedObjectsous - classe. Après l'avoir importé, je pourrais supprimer cette erreur, tout comme UIApplicationla partie deUIKit

J'espère que cela aide les autres !!!

NSPratik
la source
2

J'utilise ceci dans Swift 2.3.

1. dans la classe AppDelegate

static let sharedInstance: AppDelegate = UIApplication.sharedApplication().delegate as! AppDelegate

2.Appelez AppDelegate avec

let appDelegate = AppDelegate.sharedInstance
Ted Liu
la source
2
extension AppDelegate {

    // MARK: - App Delegate Ref
    class func delegate() -> AppDelegate {
        return UIApplication.shared.delegate as! AppDelegate
    }
}
CrazyPro007
la source
2

Depuis iOS 12.2 et Swift 5.0, AppDelegaten'est pas un symbole reconnu. UIApplicationDelegateest. Les réponses auxquelles il est fait référence ne AppDelegatesont donc plus correctes. La réponse suivante est correcte et évite le dépliage forcé, que certains développeurs considèrent comme une odeur de code:

import UIKit

extension UIViewController {
  var appDelegate: UIApplicationDelegate {
    guard let appDelegate = UIApplication.shared.delegate else {
      fatalError("Could not determine appDelegate.")
    }
    return appDelegate
  }
}
Josh Adams
la source
1
Dans swift5, votre code donnera l'avertissement "UIApplication.delegate doit être utilisé uniquement à partir du thread principal". Pouvez-vous mettre à jour la réponse.
Mahesh Narla
qui fatalErrorest fonctionnellement équivalent à un déballage forcé!
pkamb
1

Dans Swift 3.0, vous pouvez obtenir la appdelegateréférence en

let appDelegate = UIApplication.shared.delegate as! AppDelegate
Ramakrishna
la source
0

Dans le Xcode 6.2, cela fonctionne également

let appDelegate = UIApplication.sharedApplication().delegate! as AppDelegate

let aVariable = appDelegate.someVariable
v01d
la source
2
v01d, d'où avez-vous pris cela?
NSPratik