12 ответов:
это не так уж отличается от obj-c. Во-первых, вы должны указать протокол в объявлении класса, например:
class MyClass: NSUserNotificationCenterDelegateреализация будет выглядеть следующим образом:
// NSUserNotificationCenterDelegate implementation func userNotificationCenter(center: NSUserNotificationCenter, didDeliverNotification notification: NSUserNotification) { //implementation } func userNotificationCenter(center: NSUserNotificationCenter, didActivateNotification notification: NSUserNotification) { //implementation } func userNotificationCenter(center: NSUserNotificationCenter, shouldPresentNotification notification: NSUserNotification) -> Bool { //implementation return true }конечно, вы должны установить делегат. Например:
NSUserNotificationCenter.defaultUserNotificationCenter().delegate = self;
вот небольшая помощь по делегатам между двумя контроллерами вида:
Шаг 1: сделайте протокол в UIViewController, который вы будете удалять / будет отправлять данные.
protocol FooTwoViewControllerDelegate:class { func myVCDidFinish(_ controller: FooTwoViewController, text: String) }Шаг 2: объявить делегат в классе отправки (т. е. UIViewcontroller)
class FooTwoViewController: UIViewController { weak var delegate: FooTwoViewControllerDelegate? [snip...] }Шаг 3: используйте делегат в методе класса для отправки данных в метод получения, который является любым методом, который принимает протокол.
@IBAction func saveColor(_ sender: UIBarButtonItem) { delegate?.myVCDidFinish(self, text: colorLabel.text) //assuming the delegate is assigned otherwise error }Шаг 4: примите протокол в приемном классе
class ViewController: UIViewController, FooTwoViewControllerDelegate {Шаг 5: реализовать метод делегата
func myVCDidFinish(_ controller: FooTwoViewController, text: String) { colorLabel.text = "The Color is " + text controller.navigationController.popViewController(animated: true) }Шаг 6: установите делегат в prepareForSegue:
override func prepare(for segue: UIStoryboardSegue, sender: Any?) { if segue.identifier == "mySegue" { let vc = segue.destination as! FooTwoViewController vc.colorString = colorLabel.text vc.delegate = self } }и это должно сработать. Это, конечно, просто фрагменты кода, но должно дать вам представление. Долгое объяснение этого кода Вы можете перейти к моей записи в блоге здесь:
если вас интересует, что происходит под капотом с делегатом, я писала об этом здесь:
делегаты всегда смущали меня, пока я не понял, что делегат-это просто класс, который выполняет некоторую работу для другого класса. Это как если бы кто-то другой делал за тебя всю грязную работу, которую ты не хочешь делать сам.
Я написал небольшую историю, чтобы проиллюстрировать это. Читайте его на детской площадке, если хотите.
когда-то давно...
// MARK: Background to the story // A protocol is like a list of rules that need to be followed. protocol OlderSiblingDelegate: class { // The following command (ie, method) must be obeyed by any // underling (ie, delegate) of the older sibling. func getYourNiceOlderSiblingAGlassOfWater() } // MARK: Characters in the story class BossyBigBrother { // I can make whichever little sibling is around at // the time be my delegate (ie, slave) weak var delegate: OlderSiblingDelegate? func tellSomebodyToGetMeSomeWater() { // The delegate is optional because even though // I'm thirsty, there might not be anyone nearby // that I can boss around. delegate?.getYourNiceOlderSiblingAGlassOfWater() } } // Poor little sisters have to follow (or at least acknowledge) // their older sibling's rules (ie, protocol) class PoorLittleSister: OlderSiblingDelegate { func getYourNiceOlderSiblingAGlassOfWater() { // Little sis follows the letter of the law (ie, protocol), // but no one said exactly how she had to respond. print("Go get it yourself!") } } // MARK: The Story // Big bro is laying on the couch watching basketball on TV. let bigBro = BossyBigBrother() // He has a little sister named Sally. let sally = PoorLittleSister() // Sally walks into the room. How convenient! Now big bro // has someone there to boss around. bigBro.delegate = sally // So he tells her to get him some water. bigBro.tellSomebodyToGetMeSomeWater() // Unfortunately no one lived happily ever after... // The end.в обзоре есть три ключевые части для создания и использования делегата узор.
- the протокол это определяет, что работник должен сделать
- the босс класс это имеет переменную делегата, который он использует, чтобы сказать рабочему классу, что делать
- the рабочий класс что принимает протокол и делает то, что требуется
реальная жизнь
по сравнению с нашей историей старшего брата выше, делегаты часто используются для следующих практических целей приложения:
- сообщении: один класс должен послать некоторую информацию в другой класс.
- настройки: один класс хочет, чтобы другой класс, чтобы настроить его.
большая часть заключается в том, что эти классы не должны ничего знать друг о друге заранее, за исключением того, что класс-делегат соответствует нужный протокол.
я настоятельно рекомендую прочитать следующие две статьи. Они помогли мне понять делегатов даже лучше, чем документация сделал.
- что такое делегирование? - Руководство для разработчиков Swift
- Как Работает Делегирование-A Руководство для разработчиков Swift
еще одно замечание
делегаты, ссылающиеся на другие классы, которые им не принадлежат, должны использовать
weakключевое слово, чтобы избежать сильных ссылочные циклы. Смотрите ответ для более подробной информации.
я получил несколько исправлений в посте @MakeAppPie
во-первых, когда вы создаете протокол делегата, он должен соответствовать протоколу класса. Как в примере ниже.
protocol ProtocolDelegate: class { func myMethod(controller:ViewController, text:String) }во-вторых, ваш представитель должен быть слабым, чтобы избежать удержания цикла.
class ViewController: UIViewController { weak var delegate: ProtocolDelegate? }наконец, вы в безопасности, потому что ваш протокол является необязательным значением. Это означает, что его сообщение " nil " не будет отправлено в это свойство. Это похоже на условный оператор с
respondToselectorв objC но здесь вы есть все в одной строке:if ([self.delegate respondsToSelector:@selector(myMethod:text:)]) { [self.delegate myMethod:self text:@"you Text"]; }выше у вас есть пример obj-C, а ниже у вас есть быстрый пример того, как это выглядит.
delegate?.myMethod(self, text:"your Text")
здесь суть я собрал. Мне было интересно то же, и это помогло улучшить мое понимание. Откройте это в Xcode Playground чтобы посмотреть, что происходит.
protocol YelpRequestDelegate { func getYelpData() -> AnyObject func processYelpData(data: NSData) -> NSData } class YelpAPI { var delegate: YelpRequestDelegate? func getData() { println("data being retrieved...") let data: AnyObject? = delegate?.getYelpData() } func processYelpData(data: NSData) { println("data being processed...") let data = delegate?.processYelpData(data) } } class Controller: YelpRequestDelegate { init() { var yelpAPI = YelpAPI() yelpAPI.delegate = self yelpAPI.getData() } func getYelpData() -> AnyObject { println("getYelpData called") return NSData() } func processYelpData(data: NSData) -> NSData { println("processYelpData called") return NSData() } } var controller = Controller()
ДЕЛЕГАТЫ В SWIFT 2
Я объясняю с примером делегата с двумя viewControllers.In в этом случае объект SecondVC отправляет данные обратно в первый контроллер представления.
класс с объявлением протокола
protocol getDataDelegate { func getDataFromAnotherVC(temp: String) } import UIKit class SecondVC: UIViewController { var delegateCustom : getDataDelegate? override func viewDidLoad() { super.viewDidLoad() } override func didReceiveMemoryWarning() { super.didReceiveMemoryWarning() // Dispose of any resources that can be recreated. } @IBAction func backToMainVC(sender: AnyObject) { //calling method defined in first View Controller with Object self.delegateCustom?.getDataFromAnotherVC("I am sending data from second controller to first view controller.Its my first delegate example. I am done with custom delegates.") self.navigationController?.popViewControllerAnimated(true) } }в первом протоколе ViewController соответствие выполняется здесь:
class ViewController: UIViewController, getDataDelegateопределение метода протокола в первом контроллере вида (ViewController)
func getDataFromAnotherVC(dataString : String) { // dataString from SecondVC lblForData.text = dataString }во время нажима на SecondVC от Первый Контроллер Вида (ViewController)
let objectPush = SecondVC() objectPush.delegateCustom = self self.navigationController.pushViewController(objectPush, animated: true)
первый класс:
protocol NetworkServiceDelegate: class { func didCompleteRequest(result: String) } class NetworkService: NSObject { weak var delegate: NetworkServiceDelegate? func fetchDataFromURL(url : String) { delegate?.didCompleteRequest(url) } }второй класс:
class ViewController: UIViewController, NetworkServiceDelegate { let network = NetworkService() override func viewDidLoad() { super.viewDidLoad() network.delegate = self network.fetchDataFromURL("Success!") } func didCompleteRequest(result: String) { print(result) } }
очень легко шаг за шагом (100% работает и тестируется)
Шаг 1: создать метод на первом контроллере вида
func updateProcessStatus(isCompleted : Bool){ if isCompleted{ self.labelStatus.text = "Process is completed" }else{ self.labelStatus.text = "Process is in progress" } }Шаг 2: установить делегат при нажатии на второй контроллер вида
@IBAction func buttonAction(_ sender: Any) { let secondViewController = self.storyboard?.instantiateViewController(withIdentifier: "secondViewController") as! secondViewController secondViewController.delegate = self self.navigationController?.pushViewController(secondViewController, animated: true) }Шаг 3: установить делегат как
класс ViewController: UIViewController, ProcessStatusDelegate {
Шаг 4: создать протокол
protocol ProcessStatusDelegate:NSObjectProtocol{ func updateProcessStatus(isCompleted : Bool) }Шаг 5: принимать переменная
var delegate:ProcessStatusDelegate?step6: пока вернитесь к предыдущему методу делегирования вызова контроллера вида, чтобы первый контроллер вида уведомил с данными
@IBAction func buttonActionBack(_ sender: Any) { delegate?.updateProcessStatus(isCompleted: true) self.navigationController?.popViewController(animated: true) } @IBAction func buttonProgress(_ sender: Any) { delegate?.updateProcessStatus(isCompleted: false) self.navigationController?.popViewController(animated: true) }
делегаты-это шаблон проектирования, который позволяет одному объекту отправлять сообщения другому объекту при возникновении определенного события. Представьте себе, что объект A вызывает объект B для выполнения действия. Как только действие завершено, объект A должен знать, что B выполнил задачу и принял необходимые меры, это может быть достигнуто с помощью делегатов! Вот учебник реализации делегатов шаг за шагом в swift 3
Простой Пример:
protocol Work: class { func doSomething() } class Manager { weak var delegate: Work? func passAlong() { delegate?.doSomething() } } class Employee: Work { func doSomething() { print("Working on it") } } let manager = Manager() let developer = Employee() manager.delegate = developer manager.passAlong() // PRINTS: Working on it
решения выше казались немного связанными и в то же время избегали повторного использования того же протокола в других контроллерах, поэтому я пришел с решением, которое более сильно типизировано с использованием универсального типа-стирания.
@noreturn public func notImplemented(){ fatalError("not implemented yet") } public protocol DataChangedProtocol: class{ typealias DataType func onChange(t:DataType) } class AbstractDataChangedWrapper<DataType> : DataChangedProtocol{ func onChange(t: DataType) { notImplemented() } } class AnyDataChangedWrapper<T: DataChangedProtocol> : AbstractDataChangedWrapper<T.DataType>{ var base: T init(_ base: T ){ self.base = base } override func onChange(t: T.DataType) { base.onChange(t) } } class AnyDataChangedProtocol<DataType> : DataChangedProtocol{ var base: AbstractDataChangedWrapper<DataType> init<S: DataChangedProtocol where S.DataType == DataType>(_ s: S){ self.base = AnyDataChangedWrapper(s) } func onChange(t: DataType) { base.onChange(t) } } class Source : DataChangedProtocol { func onChange(data: String) { print( "got new value \(data)" ) } } class Target { var delegate: AnyDataChangedProtocol<String>? func reportChange(data:String ){ delegate?.onChange(data) } } var source = Source() var target = Target() target.delegate = AnyDataChangedProtocol(source) target.reportChange("newValue")выход: получил новое значение newValue
в swift 4.0
создайте делегат в классе, который должен отправлять некоторые данные или предоставлять некоторые функции другим классам
как
protocol GetGameStatus { var score: score { get } func getPlayerDetails() }после этого в классе, который собирается подтвердить этот делегат
class SnakesAndLadders: GetGameStatus { func getPlayerDetails() { } }
Comments