Как получить ссылку на делегата приложения в Swift?


409

Как получить ссылку на делегата приложения в Swift?

В конечном счете, я хочу использовать ссылку для доступа к контексту управляемого объекта.


8
Обратите внимание, что некоторые считают использование делегата приложения в качестве контейнера для контекста управляемого объекта или других «глобальных» объектов антипаттерном. Подумайте о том, чтобы делегат приложения передавал MOC контроллеру, а не заставлял контроллер его находить.
Кристофер Джонсон

1
@KristopherJohnson Эй, Крис, как я могу упростить внедрение зависимостей AppDelegate в контроллеры представлений? Инстанцировать контроллер представления программно и использовать рефлексию, чтобы решить, что создавать / вводить рекурсивно? Существуют ли рамки, которые могут помочь с этим? Если мне придется делать это для каждого контроллера представления вручную, мой AppDelegate будет огромным! Ох, желательно без создания фабрики для всего :)
Джимбо

1
При беглом поиске был найден Swinject, в котором также есть авто-проводка :)
Jimbo

6
Для программистов, которые не советуют помещать что-либо «постороннее» в делегат приложения, это немного глупо, потому что в документации Apple однозначно говорится, что одно "crucial role"из приложений UIApplicationDelegate- "...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

Ответы:


757

Другое решение является правильным в том смысле, что оно даст вам ссылку на делегат приложения, но это не позволит вам получить доступ к любым методам или переменным, добавленным вашим подклассом UIApplication, например к контексту вашего управляемого объекта. Чтобы решить эту проблему, просто уменьшите значение до «AppDelegate» или как там будет называться ваш подкласс UIApplication. В Swift 3, 4 и 5 это делается следующим образом:

let appDelegate = UIApplication.shared.delegate as! AppDelegate
let aVariable = appDelegate.someVariable

10
В случае, если у кого-то все еще есть проблемы, нацеливание на OS X требует, чтобы вы импортировали Какао, чтобы это работало для NSApplication.sharedApplication (). Я предполагаю, что iOS потребуется эквивалент.
smaurice

2
Это более полезный из двух ответов.
Джо

3
@zacjordaan Используя этот метод, вы получите автозаполнение для свойства, но на самом деле оно не будет работать. Таким образом, каждый раз, когда вы его используете, создается новый экземпляр класса AppDelegate. Вам лучше использовать делегата, доступного через синглтон sharedApplication. А что касается вашего второго вопроса, да, вы, вероятно, хотите использовать константу. Даже если вы изменяете свойства AppDelegate, вы, вероятно, не будете переназначать указатель на что-либо еще, и в этом случае переменная не нужна. Это полностью зависит от вас, хотя. Делайте то, что соответствует вашим потребностям.
Мик МакКаллум

2
Отличный совет! Я ошибочно думал, что AppDelegate () был синглтоном, но, подумав о том, что вы сказали, я понял, что если бы это было так, у нас не было бы шаблона sharedApplication для такого использования. Конечно, я не хочу создавать ненужные экземпляры, если мне не нужно, так что ваше постоянное объявление подойдет идеально; Спасибо.
zacjordaan

4
Я не хочу добавлять это как отдельный ответ, но чтобы получить AppDelegate с вашими собственными методами, свойствами в проекте, где используются и Swift, и Obj-c, вы должны добавить #import "AppDelegate.h" в "ProjectName-BridgingHeader .h "
Марчин

44

Swift 4.2

В Swift легко получить доступ к вашим ВК

extension UIViewController {
    var appDelegate: AppDelegate {
    return UIApplication.shared.delegate as! AppDelegate
   }
}

26

Удобные Конструкторы

Добавьте в класс AppDelegate в конце кода

Swift 5

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

Чтобы использовать ссылку AppDelegate в вашем классе?


Вызовите метод AppDelegate

AppDelegate (). setRoot ()


Было бы здорово объяснить, что делает setRoot () и когда его вызывать. Например, нормально ли вызывать его из ViewController? Из юнит-теста, где окно еще не установлено? Больше контекста было бы здорово.
Хоуман,

@Houman setRoot - это метод из AppDelegate, который может использоваться для переключения между несколькими корнями или ParentViewController и может быть любым методом. Обсуждение о том, как получить ссылку на AppDelegate для дальнейшего доступа, но надеюсь, что setRoot также должен быть ясен.
AiOsN


19

Это может быть использовано для OS X

let appDelegate = NSApplication.sharedApplication().delegate as AppDelegate
var managedObjectContext = appDelegate.managedObjectContext?

3
Или простоlet appDelegate = NSApp.delegate as AppDelegate
Владимир Прудников

1
В Swift 3 используйтеlet appDelegate = NSApplication.shared().delegate as AppDelegate
Dirk

4
В Swift 4 :NSApp.delegate as? AppDelegate
Ник

12

Вот версия Swift 2.0:

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

И для доступа к контексту управляемого объекта:

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

        let moc = delegate.managedObjectContext

        // your code here

    }

или, используя охрану:

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

    let moc = delegate.managedObjectContext

    // your code here

10

SWIFT <3

Создайте метод в классе AppDelegate для ex

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

и назвать это где-то еще, например

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

SWIFT> = 3.0

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

2
это также работает, и мне нравится идея именования sharedInstance. Спасибо!
Джон Гриффитс

2
Ваш пример будет по-прежнему создавать новый AppDelegateобъект каждый раз, когда вы AppDelegate().sharedInstance()
вызываете

1
Мне нравится это решение лучше, чем общепринятое (которое «просто», если вам придется использовать его повсеместно). Я думал об экспериментировании с extensionfor, NSApplicationпрежде чем нашел этот ответ, но это намного лучше. В настоящее время вы, вероятно, захотите использовать свойство «только для чтения», sharedно, возможно, вы захотите опубликовать обновление для Swift 3?
Патру

1
На самом деле я нахожусь в процессе рефакторинга своего кода, чтобы использовать его, static var shared : TournamentDelegate? { get { return NSApplication.shared().delegate as? TournamentDelegate } }что больше соответствует развивающемуся стилю Swift 3 - использовать вычисляемые свойства только для чтения для этого типа вещей. Я, вероятно, смогу отбросить, как ?только рефакторинг будет сделан, не так ли? (Извините, форматирование кода в комментариях - это всегда беспорядок.)
Патру

@ pxpgraphics UIApplication - одноэлементный класс, поэтому не нужно беспокоиться о множественных экземплярах.
Абхиджит


6

Попробуйте просто это:

Swift 4

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

где в вашем AppDelegate:

// MARK: - Whatever
func whateverWillOccur() {

    // Your code here.

}

5

Вот расширение, UIApplicationDelegateпозволяющее избежать жесткого кодирования имени AppDelegateкласса:

extension UIApplicationDelegate {

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

// use like this:
let appDelegate = MyAppDelegate.shared // will be of type MyAppDelegate

на Mac для NSApplicationDelegateэтого дает мне: 'Self' is only available in a protocol or as the result of a method in a class; did you mean 'AppDelegate'?. Это устарело?
Пкамб

@pkamb Я только что попробовал это в новом проекте, и у меня нет этой ошибки. Я заменил UIApplicationDelegateна NSApplicationDelegateи UIApplicationна NSApplication.
Нюг


4

это очень просто

Экземпляр делегата приложения

let app = UIApplication.shared.delegate as! AppDelegate

Вы можете вызвать метод с синтаксисом в одну строку

app.callingMethod()

вы можете получить доступ к переменной с помощью этого кода

app.yourVariable = "Assigning a value"

2

В моем случае я отсутствовал import UIKitна вершине моего NSManagedObjectподкласса. После импорта я мог бы удалить эту ошибку какUIApplication частьUIKit

Надеюсь, что это помогает другим!


2

Я использую это в Swift 2.3.

1. в AppDelegate класс

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

2. Звоните AppDelegate с

let appDelegate = AppDelegate.sharedInstance

2
extension AppDelegate {

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

2

Начиная с iOS 12.2 и Swift 5.0, AppDelegateэто не распознанный символ. UIApplicationDelegateявляется. AppDelegateПоэтому любые ответы, относящиеся к делу, больше не являются правильными. Следующий ответ является правильным и позволяет избежать принудительного развертывания, которое некоторые разработчики считают запахом кода:

import UIKit

extension UIViewController {
  var appDelegate: UIApplicationDelegate {
    guard let appDelegate = UIApplication.shared.delegate else {
      fatalError("Could not determine appDelegate.")
    }
    return appDelegate
  }
}

1
В swift5 ваш код выдаст предупреждение «UIApplication.delegate должен использоваться только из основного потока». Можете обновить ответ.
Махеш Нарла

это fatalErrorфункционально эквивалентно развертыванию силы!
Пкамб


0

В Xcode 6.2 это также работает

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

let aVariable = appDelegate.someVariable

2
v01d, откуда ты это взял?
NSPratik
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.