Делегаты по-быстрому?

Как можно сделать делегата, т.е. NSUserNotificationCenterDelegate в быстром?

15 ответов

Решение

Это ничем не отличается от 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.

В обзоре есть три ключевых части создания и использования шаблона делегата.

  1. протокол, который определяет, что должен делать работник
  2. класс босса, который имеет переменную делегата, которую он использует, чтобы указать рабочему классу, что делать
  3. рабочий класс, который принимает протокол и делает то, что требуется

Реальная жизнь

По сравнению с нашей историей о Босси-старшем брате делегатов часто используют для следующих практических применений:

  1. Связь: один класс должен отправить некоторую информацию другому классу.
  2. Настройка: один класс хочет позволить другому классу настроить его.

Самое замечательное в том, что этим классам не нужно ничего знать друг о друге заранее, за исключением того, что класс делегата соответствует требуемому протоколу.

Я настоятельно рекомендую прочитать следующие две статьи. Они помогли мне понять делегатов даже лучше, чем документация.

Еще одна заметка

Делегаты, которые ссылаются на другие классы, которые им не принадлежат, должны использовать weak ключевое слово, чтобы избежать сильных ссылочных циклов. Смотрите этот ответ для более подробной информации.

Я получил несколько исправлений к посту @MakeAppPie

Прежде всего, когда вы создаете протокол делегата, он должен соответствовать протоколу Class. Как в примере ниже.

protocol ProtocolDelegate: class {
    func myMethod(controller:ViewController, text:String)
}

Во-вторых, ваш делегат должен быть слабым, чтобы избежать сохранения цикла.

class ViewController: UIViewController {
    weak var delegate: ProtocolDelegate?
}

Наконец, вы в безопасности, потому что ваш протокол является необязательным значением. Это означает, что его "ноль" сообщение не будет отправлено в это свойство. Это похоже на условное утверждение с respondToselector в objC, но здесь у вас все в одной строке:

if ([self.delegate respondsToSelector:@selector(myMethod:text:)]) {
    [self.delegate myMethod:self text:@"you Text"];
}

Выше у вас есть пример obj-C, а ниже у вас есть Swift пример того, как это выглядит.

delegate?.myMethod(self, text:"your Text")

Вот суть, которую я собрал. Мне было интересно то же самое, и это помогло улучшить мое понимание. Откройте это на игровой площадке Xcode, чтобы увидеть, что происходит.

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

Я объясняю на примере Delegate с двумя viewControllers. В этом случае SecondVC Object отправляет данные обратно в первый View Controller.

Класс с протоколом декларации

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)
    }

}

В First ViewController Protocol согласование осуществляется здесь:

class ViewController: UIViewController, getDataDelegate

Определение метода протокола в First View Controller(ViewController)

func getDataFromAnotherVC(temp : String)
{
  // dataString from SecondVC
   lblForData.text = dataString
}

Во время нажатия SecondVC из First View Controller(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?

Шаг 6: При возвращении к предыдущему представлению контроллера вызовите метод делегата, чтобы сначала контроллер представления уведомлял данными

@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)

}

Простой пример:

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

Вот простой пример кода делегата:

      //MARK: - Protocol ShowResult
protocol ShowResult: AnyObject {
       func show(value: Int) 
  }

//MARK: - MyOperation Class
class MyOperation {
weak var delegate: ShowResult?

func sum(fNumber: Int, sNumber: Int) {
    delegate?.show(value: fNumber + sNumber)
  }
}

//MARK: - ViewController Class
class ViewController: UIViewController,ShowResult {
var myOperation: MyOperation?

override func viewDidLoad() {
    super.viewDidLoad()
    loadMyOperation()
    myOperation?.delegate = self
    myOperation?.sum(fNumber: 100, sNumber: 20)
 }

private func loadMyOperation() {
    if myOperation == nil {
        myOperation = MyOperation()
     }
 }

func show(value: Int) {
    print("value: \(value)")
   }
}

Делегаты - это шаблон проектирования, который позволяет одному объекту отправлять сообщения другому объекту, когда происходит определенное событие. Представьте, что объект A вызывает объект B для выполнения действия. Как только действие завершено, объект A должен знать, что B выполнил задачу, и предпринять необходимые действия, это может быть достигнуто с помощью делегатов! Вот руководство по реализации делегатов шаг за шагом в Swift 3

Ссылка на учебник

Вот сценарий делегата из реальной жизни.
Давайте создадим наши собственные UITextField и UITextFieldDelegate.

      // THE MYSTERIOUS UITEXTFIELD

protocol UITextFieldDelegate {
    func textFieldDidChange(_ textField: UITextField) -> Void
}

class UITextField {
    var delegate: UITextFieldDelegate?
    private var mText: String?
    var text: String? {
        get {
            return mText
        }
    }
    
    init(text: String) {
        
    }
    
    init() {
        
    }
    
    func setText(_ text: String) {
        mText = text
        delegate?.textFieldDidChange(self)
    }

}
      // HERE IS MY APP

class Main {
    
    let textfield = UITextField()
    
    func viewDidLoad() {
        print("viewDidLoad")
        textfield.delegate = self
        textfield.setText("Hello")
    }
    
}

extension Main: UITextFieldDelegate {
    
    func textFieldDidChange(_ textField: UITextField) {
        print(textField.text ?? "No string")
    }
    
}

let main = Main()
main.viewDidLoad()

Представленные выше решения казались немного связанными и в то же время избегали повторного использования одного и того же протокола в других контроллерах, поэтому я пришел с решением, которое более строго типизировано с использованием универсального стирания типов.

@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

В Свифт 5

Я новичок, я думаю, что это самый простой способ понять практический сценарий.

Примечание: любые импровизации приветствуются

      protocol APIService {
   func onSuccessResponse() -> AnyObject
   func onFailureResponse() -> AnyObject
}

class APIHelper{

var delegate : APIService?

func postUsersDataAPI() {
    //assuming API communication is success
    if(success){
       let _: AnyObject? = delegate?.onSuccessResponse()
    }else if(failure){
       let _: AnyObject? = delegate?.onFailureResponse()
  }
 }

func getAllUsersAPI() {
    //assuming API communication is success
   if(success){
       let _: AnyObject? = delegate?.onSuccessResponse()
    }else if(failure){
       let _: AnyObject? = delegate?.onFailureResponse()
  }
 }
}


class ViewController:UIViewController,APIService {

func onSuccessResponse() -> AnyObject {
    print("onSuccessResponse") as AnyObject
}

func onFailureResponse() -> AnyObject {
    print("onFailureResponse") as AnyObject
}

@IBAction func clickBtnToPostUserData(_ sender: Any) { 
    let apiHelper = APIHelper()
    apiHelper.delegate = self
    apiHelper.postAPI()
}

В Swift 4.0

Создайте делегата в классе, который должен отправить некоторые данные или предоставить некоторые функции другим классам.

подобно

protocol GetGameStatus {
    var score: score { get }
    func getPlayerDetails()
}

После этого в классе, который собирается подтвердить этот делегат

class SnakesAndLadders: GetGameStatus {
    func getPlayerDetails() {

 }
}
Другие вопросы по тегам